How to guarantee an element will have a particular height - javascript

Say that I have this element on my page:
<div style="height: 1em;"> </div>
I want to use JavaScript to measure the height of the div to figure out how many px are equivalent to 1em for that element.
So if I did:
document.querySelector('div').getBoundingClientRect()
Then I might get 16.
But what if users can inject arbitrary styles onto this webpage? What if they do something like:
div { border: 1px solid black; }
Then I would get 18, because of the unexpected border applied to all div elements.
To avoid this, I could add a laundry list of styles to the div to remove potential "unexpected styles:"
<div style="border: 0; margin: 0; padding: 0; height: 1em;"> </div>
But is that list of styles comprehensive? If not, what other styles do I need? Or is there a better way to make this calculation?

Set the font-style: 1em !important; on the element, and get the font size in px using Window#getComputedStyle:
var fontSize = window.getComputedStyle(div).fontSize;
console.log(fontSize);
<div id="div" style="font-size: 1em;"></div>
My previous not bullet proof answer:
This fails if the user uses borders and/or paddings which height is greater than 16.
You can use box-sizing: border-box on the element. With this box sizing, the borders and the paddings don't increase the dimensions of the element. The content area is the original width/height minus any paddings and borders.
console.log(div.getBoundingClientRect().height);
div {
padding: 3px;
border: 2px solid black;
}
<div id="div" style="height: 1em; box-sizing: border-box;">

Related

Setting `element.style.height` not working as expected if `element.style.box-sizing` is `border-box`

I am having an understanding problem with the following code:
let myDiv1 = document.getElementById("myDiv1");
alert("Click me to make 'Hello' vanish");
myDiv1.style.height = "0px";
let myDiv2 = document.getElementById("myDiv2");
alert("Click me to make 'World' vanish");
myDiv2.style.height = "0";
.myClass1 {
box-sizing: border-box;
overflow: hidden;
padding-top: 2em;
padding-bottom: 2em;
background-color: yellow;
}
.myClass2 {
box-sizing: content-box;
overflow: hidden;
padding-top: 2em;
padding-bottom: 2em;
background-color: orange;
}
<body>
<div id="myDiv1" class="myClass1">
Hello
</div>
<div id="myDiv2" class="myClass2">
World
</div>
</body>
I understand the behavior of the second (orange) div: It has box-sizing: content-box;, so its height does not include the padding or the borders. Hence, when its height is set to 0, it shrinks basically by the height of the text "World", but the padding is left as-is. Since the padding exceeds the original text height, the text is still visible in the padding. Only that part of padding which is now outside the div (due to the reduced height) becomes invisible (due to overflow: hidden;).
I do not understand the behavior of the first (yellow) div, though. It has box-sizing: border-box;, so its height does include the padding and the borders. Hence, when its height is set to 0, it should shrink to "real" zero height, meaning that the text, the padding and the borders then should be outside the div and thus should be invisible (due to overflow: hidden;).
Can anybody explain why this is not the case and why the first div behaves just like the second div?
P.S. Tested in Firefox and Chrome, both up-to-date (production channel) at the time of writing this.
border-box tells the browser to account for any border and padding in the values you specify for an element's width and height. If you set an element's width to 100 pixels, that 100 pixels will include any border or padding you added, and the content box will shrink to absorb that extra width. This typically makes it much easier to size elements. ref
Here is an example to better ilustrate your issue:
.box {
display: inline-block;
padding-top: 2em;
padding-bottom: 2em;
border: 2px solid blue;
background: linear-gradient(red, red) content-box, orange;
height: 100px;
animation:move 5s linear infinite alternate;
}
#keyframes move{
to {
height:0;
}
}
<div class="box">
World
</div>
<div class="box" style=" box-sizing: border-box;">
World
</div>
The first example is the trivial one where we decrease the height (red area) until 0 and the animation never stop.
In the second case the height include the padding and border so before reaching 0 the content area is already 0 that's why the animation seems to stop because we cannot decrease more than 0 and the border/padding already consumed all the space.
It's logical that when height is equal to 0 both are the same since in the first one we tell the browser that the content area should be 0 (we don't care about padding/border) and in the second case we told the browser to account for the padding/border into the height we specified so we have less room for the content area and since we cannot have less than 0 then its 0.
In other words, you aren't setting the total height that will be split between the content area, padding and border but you are setting a height and the browser is shrinking it as much as possible to include the border and padding.
Related for more examples and details: box-sizing: border-box with no declared height/width

How to fill page horizontally with divs without empty space at the end

I am having this simple but frustrating CSS problem. I am trying to fill a page completely with divs/boxes. The problem is, that these boxes have same width all the time, therefore boxes won't fill up evenly. Let me demonstrate this:
Fiddle.
CSS:
.box {
float: left;
width: 200px;
height: 200px;
margin: 0px 10px 10px 0px;
background-color: #000000;
}
HTML:
<div id="boxes">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
This is OK:
But if user has a smaller window size, it will go like:
This would be the best solution, resizing boxes to fit screen horizontally evenly:
What would be the best solution to make them fit whole page when window is resized? Preferably CSS-only (if possible).
Here is a working example.
IMO, the solution depends om your needs. If are able to scale the images, then the 33% rule offered by others here is probably acceptable. However, you may wish to limit how far the size can be go (min-width). Also, this is going to totally bork your aspect ratios, which you might find unacceptable.
One alternate solution would be to have a 'viewport' div on on-top of a larger div that allows some bleed-over to minimize the 'gosh, it's only one pixel only over' effect (where you get a huge, gaping blank column. This solution allows the cards to bleed out of the viewport a bit before forcing a new column. And it is CSS-only. This is the provided example. Test it out by changing the outer container width and height ('my-outer'):
/* CSS */
.my-outer {
position : relative;
box-sizing : border-box;
width : 350px;
height : 450px;
border : 1px solid red;
overflow-x : hidden;
overflow-y : auto;
}
.my-inner {
position : relative;
box-sizing : border-box;
border : 1px solid green;
width : 120%;
}
.my-card {
box-sizing : border-box;
float : left;
margin : 10px;
width : 100px;
height : 100px;
font-size : 50px;
line-height : 100px;
text-align : center;
font-weight : 800;
background : #aaf;
color : #fff;
border-radius : 2x;
box-shadow: 0 0 16px -2px #888;
}
<!-- HTML -->
<div class="my-outer">
<div class="my-inner">
<div class="my-card">1</div>
<div class="my-card">2</div>
<div class="my-card">3</div>
<div class="my-card">4</div>
<div class="my-card">5</div>
<div class="my-card">6</div>
<div class="my-card">7</div>
<div class="my-card">8</div>
<div class="my-card">9</div>
<div class="my-card">10</div>
<div class="my-card">11</div>
<div class="my-card">12</div>
<div class="my-card">13</div>
<div class="my-card">14</div>
<div stlye="clear : both;"></div>
</div>
Another alternate solution, which would probably provide the best user experience, would be to resize the container in steps. This would require some JavaScript, but can be fairly easy to quite difficult to implement depending about the environment. And yes, I have done this sort of thing before ;)
Try giving the container div boxes a width of the max amount of boxes + the margin for each box. In your example that would be 200 * 3 + 30. This is given that you only want three boxes per row.
something like
html:
<div class="box></div>
<div class="box></div>
<div class="box></div>
<div class="box></div>
<div class="box></div>
<div class="box></div>
css:
.box{
height: 100px;
width: 33%;
}

how to decrease the height of content area for <p> with css?

Could anyone tells me how to decrease the height of the content area for p tag with css?
I want to,
1. bring the bottom orange dotted line closer to the text above. (border-bottom: 3px orange dotted;)
2. reduce the height of the yellow highlighting box. (body { background-color:yellow })
adjusting the properties "line-height" and "height" don't help...
Thanks!
You should be able to change the height with the "line-height" property make sure there is not another css overwriting it. to make sure you can add !important at the end like this:
p {
line-height: 1em !important;
}
if that worked go back to your code and make sure you dont have another element changing the line-height
take the margin and padding off your p tag.
p {
margin: 0;
padding: 0;
}
if that does not work for you put it in a div with a specified height;
<div class="myDiv">
<p>your p content</p>
</div>
style;
.myDiv {
margin: 0;
padding: 0;
height: 300px; //whatever height you want
width: 300px; //whatever width you want
}

Align div with first vertically center div

I have a page, where I'm showing images side by side according to the category they belong to, each image array begins with the category it belongs to. Images vary in their width & height, but are put into a div with an absolute height of 330px.
CSS:
.front-index {
margin: 0 1em 0 2em;
}
.front-work {
margin: 0 2em 2em 0;
display: table;
width: 66px;
position: relative;
height: 330px;
background-color:#f0f0f0;
}
.front-work img {
margin: .3em 0 .3em 0;
}
.wraptocenter {
display: table-cell;
text-align: center;
vertical-align: middle;
}
.wraptocenter * {
vertical-align: middle;
}
.front-index,
.front-work {
float: left;
}
HTML:
<div class="front-index"><p>How to get<br /> this text on the same line with<br /> yellow image on the right?</p></div>
<div class="front-work">
<div class="wraptocenter">
<img width="162" height="250" src="http://images.fanpop.com/images/image_uploads/Yellow-Wallpaper-yellow-646738_800_600.jpg"/>
</div>
</div>
<div class="front-work">
<div class="wraptocenter">
<img width="250" height="166" src="http://www.takenseriouslyamusing.com/wp-content/uploads/2012/08/Blue.png"/>
</div>
</div>
…
JSFIDDLE: http://jsfiddle.net/rCAKa/9/
I'd like to align the text to the same line as the first image on the right.
What I had in mind, is that may-be this should be done in jquery. Ie. somehow measure the image distance from the top inside the .front-work div and then assign the value to the .front-index div as an inline code (top: whatever px ).
Maybe someone of you have faced this kind of problem and know a solution to this kind of problem? CSS or JS.
In my humble opinion I don't think that what you're doing is possible through CSS - it requires some simple JavaScript trickery because you have to know the relative position (from the top of the container) of the first image on the right in order to position the text - something which CSS isn't quite designed for.
The strategy in JS would be:
Loop through each element with text that you want to position
Fetch the vertical top offset of the first image to the right (relative to containing parent)
Set top padding matching to top position of image. Alternatively, you can set the top position, paddings or margins of the child elements, or other ways to reposition the text.
$(document).ready(function() {
$(".front-index").each(function() {
var fromTop = $(this).next().find("img").position().top;
$(this).css({
"padding-top":fromTop
});
});
});
I have forked your fiddle, and you can see it in action here - http://jsfiddle.net/teddyrised/LT54V/1/
p/s: On a related note, .wraptocenter * { } is probably not the best (as in, most efficient) selector out there, because if you have many child elements in the element (who may or may have even more child elements), CSS will have to iterate through all of them. Instead, try using .wraptocenter > * { } or just .wraptocenter img { } :)
I first tried to solve the problem using css. After a while I figured out the following logics:
Create a div with the same height as the cell on the right with the display set as table
Make a table-cell div in the first one that centers vertically
In this div make another subdiv with the same height as the image.
The HTML code is then this:
<div class="front-index">
<div class="front-index-inner">
<div style="height:250px;">
<p>How to get<br /> this text on the same line with<br /> yellow image on the right?</p>
</div>
</div>
</div>
and as my CSS part this:
.front-index {
margin: 0 1em 0 2em;
display: table;
height: 330px;
overflow: hidden;
}
.front-index-inner {
display: table-cell;
width: 100%;
vertical-align: middle;
}
You can see the result over here: http://jsfiddle.net/rCAKa/10/
I hope this brings a solution to you that is clear, understandable and useful.
Greetings,
Jef

How to refresh the size of a div after adding elements to it

I have an element like this:
<div id="content" style="border: 2px solid black">
</div>
And through JQuery I add some new stuff:
$("#content").append($('<div></div>').addClass("box"));
where
.box { margin: 10px; padding: 10px; border: 1px solid black }
But the outer div does not resize when I do this, so I get an inner box that is sticking out of a solid outer box. How can I get the outer box to resize itself when I add this inner box?
Correct the selector if it's not a typo
$("#content") // id="content" (correct)
$("content") // tagName = content
And change the display of the div to inline-block
#content {
display: inline-block;
}
Then the div will not occupy the whole row.
try this:
js
$('#content').append('<div class="box"> </div>');
html
<div id="content" style="border:2px solid black;overflow:hidden;">
</div>
I hope his help!
#content is not resizing, since it's width is probably set in your CSS.
Either make it wider, or specifically size it appropriately.
Looks like #content must be over 40px wide, since the inner div has 10 margin and 10 padding, which is 20 on the left and 20 on the right.
So, something like:
$("#content").css("width","100%").append($('<div></div>').addClass("box"));
Or better yet, set up your CSS at the right width to begin with:
#content { width: ... ; }
If you are floating .box within #content then set the overflow of #content to auto(or hidden), otherwise the outer box doesn't "see" the floating inner boxes:
#content { overflow: auto; }
In my case I added:
#property { overflow: auto; }
and now size of elements is being recalculated when I show or hide elements.

Categories