CSS grid layout changing column width with javascript - javascript

I try setting up a CSS grid layout as follows
.wrapper {
width: 800px;
display: grid;
grid-template-columns: repeat(3, 200px);
grid-template-rows: repeat(5, 200px);
}
Is it possible to locate grid-template-columns in JS then re-size the columns? I came across a situation where I could find it (lost the code) but when I tried changing it, Chrome DevTools say the value is computed and cannot be changed.
Any help pointing me in the right direction (or other ways to do it, but use of grid is a must) is highly appreciated.
Thanks.

#MikeC, if you're not opposed to using jQuery, you can change the column width using jQuery's .css() function, which
Get the value of a computed style property for the first element in
the set of matched elements or set one or more CSS properties for
every matched element.
You can read more on it in jQuery's documentation for the function here.
Also, just so you can see it in action, I put together a codeply project that you can see it in action. If you click anywhere on the grid, it will resize (only once though). It's a primitive example.
Here's the jQuery code it uses.
$( "#grid" ).one( "click", function() {
$( this ).css( "grid-template-columns", "repeat(2, 400px)" );
});

#MikeC You didn't tell anybody how you got it to work.
Assuming you have a button or some event that calls a toolExpandToggle() and assume that your class name for your grid CSS definition is called "canvas" then you can do something like this.
In the CSS I have:
#media only screen and (min-width: 768px) {
.canvas {
grid-gap: .0em;
grid-template-columns: 50px auto; /* the values are the toolbar, content */
grid-template-rows: 50px auto 25px; /* The values are o365Nav (O365 stardard), content, statusbar. Note: o365Nav heigth is the padding value used by the modal menu. */
grid-template-areas:
"o365Nav o365Nav"
"tool content"
"statusbar statusbar";
}
}
In the HTML I have a button. Notice that I have my widths defined as data items where 50 matches the CSS. In any case these values will replace the CSS when used.
<div class="tool" id="pl-tool" data-collasped="50"; data-expanded="200";>
<div class="spacer"></div>
<button class="tool-ms-button"><span class="ms-Icon ms-Icon--GlobalNavButton tool-ms-icon" aria-hidden="true" onclick="toolExpandToggle('pl-tool')"></span></button>
<!-- now the tool bar buttons -->
<div><button class="tool-button">item-a</button></div>
<div><button class="tool-button">item-a</button></div>
</div>
Then I have a javascript function:
function toolExpandToggle(target) {
let id = document.getElementById(target);
let c = id.dataset.collasped;
let e = id.dataset.expanded;
let w = document.getElementsByClassName('tool')[0].offsetWidth;
if(w < e) {
document.getElementsByClassName('canvas')[0].style.gridTemplateColumns = e + 'px auto';
}
else {
document.getElementsByClassName('canvas')[0].style.gridTemplateColumns = c + 'px auto';
}
}
In my case I only had two columns.
When I click a button I call the toggle method and change it to the data value.
I hope this gets someone else a little further down the track.

Related

JS. Detect hidden child with parent overflow:hidden

I'm looking for simple way to detect, if child element of parent with overflow:hidden is visible within parent (it's not hidden by overflow).
I found something like this:
http://www.useallfive.com/thoughts/javascript-tool-detect-if-a-dom-element-is-truly-visible/
but i wonder maybe there is simpler solution.
Thanks in advance!
Assuming you want a vanilla js solution, try this:
function isVisible (parent, child) {
return !(
(child.offsetLeft - parent.offsetLeft > parent.offsetWidth) ||
(child.offsetTop - parent.offsetTop > parent.offsetHeight)
)
}
Basically "if the difference between the start of the parent element and the start of the child element is greater than the actual width or height of the parent, it's considered not visible"
Run the following snippet for an example:
var parent = document.getElementById('parent');
[].slice.call(document.querySelectorAll('.child')).forEach(function (child, i) {
console.log(i + ' is visible?', isVisible(parent, child));
});
function isVisible(parent, child) {
return !(
(child.offsetLeft - parent.offsetLeft > parent.offsetWidth) ||
(child.offsetTop - parent.offsetLeft > parent.offsetHeight)
)
}
* {
box-sizing: border-box;
}
#parent {
width: 200px;
height: 100px;
white-space: nowrap;
background: lightblue;
}
.child {
display: inline-block;
width: 75px;
height: 100%;
border: 1px solid green;
}
<div id="parent">
<div class="child">0</div>
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
You can do the following things:
check if the element has height and width that are bigger than 0px
check if the element display CSS property is not "none", preferably "block"
check if the element positioning is valid and if so, check if it´s "top" property is not bigger than the parent´s height
Same thing for left - if it is not bigger than parent´s width
When checking "width", check offsetWidth and clientWidth, those will show actual numbers as displayed to the client.
I had a similar requirement, but mine was a bit more complicated because the overflow: hidden element wasn't the first parent, it was like 5 or 6 elements away.
Just spend a whole day trying to do it with solutions from the internet(I've tried the repo you mentioned as well), but nothing worked.
So I've made this repo by myself (only JS, 2kb sized) https://github.com/LuizAsFight/is-element-visible.
It might help you, basically I just get the target element and climb the tree searching if any parent has a overflow:hidden, once I found it I get the parent's rect size, and check if the target element rect is inside the parent (visually, pixels)
for using it you just need to
import isVisible from 'is-element-visible';
const el = document.getElementById('id');
isVisible(el);
I hope it helps you, Best.

Change display property and id attribute

I have 2 sections:
<section class="notes animate" id="need" style="background:#fff; height:900px; padding-top:70px;">
<!--stuff --->
</section>
<section class="focus" id="need" style="display:none;">
<!--stuff --->
</section>
I want to display the second section when window is lowered to width less than 1043px. And hide the first section by display:none
Update:
How can I remove id attribute of first section, when width is less than 1043?
You should use CSS media queries. You can read more about it here: http://www.w3schools.com/css/css_rwd_mediaqueries.asp
For example:
#media only screen and (max-width: 1043px) {
section.focus {
display: block;
}
}
Firstly you cannot use same ID for more than one div. So change the id of one div.
And to hide the second div and show the first div:
Use CSS:
#media only screen and (max-width: 1043px) {
.focus {
display: block;
}
.notes {
display: none;
}
}
In response to your requirement for removing the ID attribute, try the following JavaScript. It can only do it once however, and if you are interested in performance you should consider investigating debounce/throttle for the resize handler. (http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/)
$(window).on('resize', function() {
if($(window).width() < 1043) {
$('.notes').removeAttr('id');
$(window).off('resize');
}
});
However, the media queries answers are the correct approach to show/hide based on screen width.

Change or animate height to css default in jquery

I have a responsive website with different height setting for a header bar.
In my javascript at some point, I change this value to a fixed size :
$('#header').animate({marginTop: 0, height:80});
But at another point in my code, I would like this to revert to the original state.
How can I animate it back to the default behavior?
In other words, animating the remove inline css...
I tried
$('#header').animate({marginTop: 20, height:'inherit'});
but this doesn't work.
The original css is this :
#header { margin-top:20px; width:100%; height: 80px; background-color: #000; }
#media only screen and (min-width: 768px) and (max-width: 960px)
{
#header{height:100px;}
}
#media only screen and (max-width: 767px)
{
#header{height:auto; padding-bottom: 1px;}
}
Failed solution 1:
storing the height value:
This cannot be done because a lot of users are resizing their window between the moment where the value would be stored and the moment of restoring the stored value..
Failed solution 2:
animating to 'nothing', juste an empty string, fails, Jquery interprets this as 0 and animates the height to zero pixels.
You could use like this:
var original = $('#header').css('height');//gets original height
$('#header').animate({marginTop: 0, height:80});
Then revert use this:
$('#header').animate({marginTop: 0, height:original});
Considering you have HTML like below
<div class="item">
<div class="block"></div>
<div class="info">
My info
</div>
</div>
You can do something like this:
jQuery(document).ready(function($) {
$(".item").mouseleave(function(){
$(this).find('.info').stop().css('marginTop', '0');
}).mouseenter(function(){
$(this).find('.info').animate({ marginTop: '-50px', opacity: 0.5 }, 1000);
});
});
Demo
Try without height value or leave there just empty value height: ' '
You'll have to store the original value somewhere. I recommend this -
$('#header').data('height', $(this).height()).animate({marginTop: 0, height:80});
Then when you are ready to revert -
var oldHeight = $('#header').data('height');
$('#header').animate({marginTop: 20, height: oldHeight });
EDIT --
Do you have any other inline styles for the div?
If not, you can simply use removeAttr and remove the style property.

Created div elements' random margins not working

Problem and source code
I'm trying to create <div>s within another <div> at the click of a button. When the button is clicked, a new inner <div> is created (within the outer <div>) with a unique id. I have this part working but here's where I'm running into an issue: I want each inner <div> to have a random margin-top.
Javascript
function pressButton() {
number += 1;
makeDiv(number);
};
function makeDiv(x) {
var innerDiv = document.createElement("innerDiv" + x);
outer.appendChild(innerDiv);
innerDiv.setAttribute("style", "margin-top:" + Math.floor(Math.random()*51) + ";display:inline-block;width:48px;height:48px;background-color:#000;");
};
CSS:
#outer {
position:absolute;
white-space:nowrap;
height:118px;
overflow:auto;
width:100%;
padding:2px;
}
Result (after button is clicked 4 times)
<div id="outer">
<innerDiv1 style="margin-top:15;display:inline-block;width:48px;height:48px;background-color:#000;"></innerDiv1>
<innerDiv2 style="margin-top:23;display:inline-block;width:48px;height:48px;background-color:#000;"></innerDiv2>
<innerDiv3 style="margin-top:37;display:inline-block;width:48px;height:48px;background-color:#000;"></innerDiv3>
<innerDiv4 style="margin-top:0;display:inline-block;width:48px;height:48px;background-color:#000;"></innerDiv4>
</div>
The result (which I got from inspecting the inner elements in my browser) looks like everything worked - all the margin-tops are random like I wanted. However, the visual result is this:
As you can see, the black inner <div>s all have the same margin-top. What am I doing wrong? How can I make the created <div>s all have random margin-tops?
The CSS spec requires that a length (other than zero) that is missing a unit be treated as an error (and thus ignored). Therefore, add px to the end of your generated margin number, and all should be well.
Live Demo
Description
This happens, because you set the display:inline-block; property. This makes them all to be in one line, so they will allign to the innerDivx that has the highest margin-top.
Delete the display:inline-block; property and give them float:left;. If you want to keep the gap between them, also add margin-left:5px;. And don't forget that margin-top's value needs a unit. I think you wanted to use px.
Also <innerDivx> is not a valid HTML tag. You should change them to a <div> and use innerDivx as an id attribute. Also your tags use almost the same CSS styles so you should put the same ones to a class and add the class instead.
Full solution code
HTML
<button id="button1">Add box</button>
<div id="outer"></div>
JavaScript
var number = 0;
document.getElementById("button1").addEventListener("click", pressButton, false);
function pressButton() {
++number;
makeDiv(number);
};
function makeDiv(x) {
var innerDiv = document.createElement("div");
outer.appendChild(innerDiv);
innerDiv.className += " box";
innerDiv.setAttribute("id", "innerDiv" + x);
innerDiv.setAttribute("style", "margin-top:" + Math.floor(Math.random()*51) + "px;");
};
CSS
#outer {
position: absolute;
white-space: nowrap;
height: 118px;
overflow: auto;
width: 100%;
padding: 2px;
}
.box {
float: left;
width: 48px;
height: 48px;
background-color: #000;
margin-left: 5px;
}
This is likely caused by the position model used for inline-block elements - they're all being vertically-aligned at their bottom line in a row.
I suggest that you simplify this and use position: block with float: left
http://jsfiddle.net/2y5bJ/4/
I also suggest that you stick to standard elements to ensure cross-browser compatibility - don't create your own elements called innerDiv1 etc, but use div elements with unique IDs.
function makeDiv(x) {
var innerDiv = document.createElement("div");
outer.appendChild(div);
innerDiv.setAttribute('id', 'innerDiv' + x);
innerDiv.setAttribute("style", "margin-top:" + Math.floor(Math.random()*51) + "px;");
};
I think there is no tag available with name
<innerDiv1>
This may be the cause.

Button auto size in Jquery Mobile

I am developing a jquery/PhoneGap application. I have been trying hard to get the buttons behave the way I want to. In short I am trying to achieve the following:
I put a set of six Jquery-Mobile buttons (mini, normal or button-group).
The above set needs to be in one horizontal line so I have put them in a div.
The numbers of buttons and its text dynamically changes, so I need a CSS/JS trick that allows me to resize the button size and text based on the div/screen size. When I started with Jquery mobile (two weeks ago), I thought that this will be a basic functionality :) but alas !
Some code that I am trying right now is:
//TO CREATE BUTTONS
for(var button_id=0; button_id < window.g_maxLength/2; button_id++){
var bt_id= "<button class =\"tile\" data-theme=\"e\" data-inline=\"true\" data-mini=\"true\" id =\"button_tid"+button_id+"\";>.</button>";
$("#buttoncontainer1").append($(bt_id));
}
//HTML
<div id="tiled" align="center">
<div data-role="controlgroup" data-type="horizontal" id="buttoncontainer1">
<!-- Button will be added by JS-->
</div>
</div>
//CSS
#tiled {
align:center;
height:23%;
position:absolute;
text-align :center;
padding: 1px;
width:90%;
top:73%;
margin-right:4%;
margin-left:4%;
background-color:#b0e0e6;
border-radius: 10px;
border-width: 3%;
border-style:double;
Right now what I have is works fine on small screen devices, but as soon as I open my app in large screen device the buttons look very small with lot of empty spaces. Any help here will be appreciated !!
PS: Also used media queries - but they somehow do not work on jquery-mobile.
#media (min-width: 500px) {
html { font-size: 120%; }
}
Here's a workaround for auto-adjust width and font-size of buttons.
Demo: http://jsfiddle.net/Palestinian/UYa4Y/
// Number of buttons
var buttons = $('[data- role=controlgroup]').find('a').length;
// Parent div width
var btn_width = $('#tiled').width() / buttons;
// Remove left/right button padding
$('.ui-btn-inner').css({
'padding-left': 1,
'padding-right': 1
});
// Set button new width
$('.ui-btn-inner').width(btn_width - 4);
// Adjust font-size for each button based on text
$('.ui-btn-text').each(function () {
while ($(this).width() > $('.ui-btn-inner').width()) {
var font = parseFloat($(this).css('font-size')) - 1 + "px";
$(this).css('font-size', font);
}
});

Categories