Why doesn't viewport width work for borders? - css

I want to fit the child element perfectly inside its parent.
The correct height and width for the child seemed to be 14vw. I got this number by subtracting 2vw (the border amount from the parent and child) from 16vw, which is the parent's width and height. Yet when I resize my browser, there is a noticeable gap between the child's bottom border, and the parent. There is also a smaller gap between the right borders.
It seems that viewport width isn't behaving as I expected it to. Any explanation as to why this is the case?
I also noticed that when I inspect the border element in the developer tools, it is always an integer. If viewport width is 1% of the browser width, it seems that this should not be the case.
body {
height: auto;
width: auto;
margin: 0 auto;
}
.container {
width: 16vw;
height: 16vw;
border: 1vw solid black;
margin: 0 auto;
}
.child {
width: 14vw;
height: 14vw;
position: relative;
border: 1vw solid #654321;
}
<body>
<div class='container'>
<div class='child'></div>
</div>
</body>

Actually, floating point sizes are correct. You can see https://developer.mozilla.org/en-US/docs/Web/CSS/length or https://www.w3.org/TR/2005/WD-css3-values-20050726/. It says:
Values of the CSS data type can be interpolated in order to allow animations. In that case they are interpolated as real, floating-point, numbers. The interpolation happens on the calculated value. The speed of the interpolation is determined by the timing function associated with the animation.
I guess your situation happens because browser can't render for example 0.5px border width so it always has to work with rounded integer border values.
You can actually fix this by letting the internal .child fill the entire space and including its own border size to its dimensions:
width: 100%;
height: 100%;
box-sizing: border-box;
See: https://jsfiddle.net/dsLpa7kg/

Related

How to set an item with position absolute at the exact location everytime CSS

I have a Grid template and I am using a countdown timer with React, that returns how many seconds are left. Unfortunately, I need to use it in a different child div, because there is a function I am using. I can edit it but it would take lots of refactoring and testing everything again, so I would prefer not to.
Here is my .css code:
.countdown{
position: absolute;
top: 11.4%;
left: 70.4%;
font-size: 14px;
color: red;
}
When the screen is smaller, it is positioned as I want to but as the width gets bigger, the element goes more to the left (so it doesn't work with percentage). And the problem is that if I want a media-query it would take almost every single width resolution option. So is there another way to position the element with the absolute attribute and it doesn't get too much moved from its position in the different resolution?
If your parent width and height was set with viewport sizes vh,vw It would be at the same position in any device. because the parent is responsive and we are your using percentage which means it always be 70% from the left. if the screen size is 100px it will be 70px from the left & screen size is 1000px it will be 700px from the left. I hope it makes sense.
.countdown {
position: absolute;
top: 11.4%;
left: 70.4%;
font-size: 14px;
color: red;
outline: 1px solid red;
}
.parent {
position: relative;
width: 80vw;
height: 80vh;
outline: 1px solid red;
}
<div class="parent">
<div class="countdown">
09:00
</div>
</div>
Use pixels instead of percentages for your top and left values.

button height in percent makes it flat [duplicate]

I am trying to set a <div> to a certain percentage height in CSS, but it just remains the same size as the content inside it. When I remove the HTML 5 <!DOCTYTPE html> however, it works, the <div> taking up the whole page as desired. I want the page to validate, so what should I do?
I have this CSS on the <div>, which has an ID of page:
#page {
padding: 10px;
background-color: white;
height: 90% !important;
}
I am trying to set a div to a certain percentage height in CSS
Percentage of what?
To set a percentage height, its parent element(*) must have an explicit height. This is fairly self-evident, in that if you leave height as auto, the block will take the height of its content... but if the content itself has a height expressed in terms of percentage of the parent you've made yourself a little Catch 22. The browser gives up and just uses the content height.
So the parent of the div must have an explicit height property. Whilst that height can also be a percentage if you want, that just moves the problem up to the next level.
If you want to make the div height a percentage of the viewport height, every ancestor of the div, including <html> and <body>, have to have height: 100%, so there is a chain of explicit percentage heights down to the div.
(*: or, if the div is positioned, the ‘containing block’, which is the nearest ancestor to also be positioned.)
Alternatively, all modern browsers and IE>=9 support new CSS units relative to viewport height (vh) and viewport width (vw):
div {
height:100vh;
}
See here for more info.
You need to set the height on the <html> and <body> elements as well; otherwise, they will only be large enough to fit the content. For example:
<!DOCTYPE html>
<title>Example of 100% width and height</title>
<style>
html, body { height: 100%; margin: 0; }
div { height: 100%; width: 100%; background: red; }
</style>
<div></div>
bobince's answer will let you know in which cases "height: XX%;" will or won't work.
If you want to create an element with a set ratio (height: % of it's own width), use the aspect-ratio property. Make sure height is not explicitly set on the element for it to work. https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio
.square {
width: 100%;
height: unset;
aspect-ratio: 1 / 1;
}
Historically, the best way to do this was to set the height using padding-bottom. Example for square:
<div class="square-container">
<div class="square-content">
<!-- put your content in here -->
</div>
</div>
.square-container { /* any display: block; element */
position: relative;
height: 0;
padding-bottom: 100%; /* of parent width */
}
.square-content {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
}
The square container will just be made of padding, and the content will expand to fill the container. Long article from 2009 on this subject: http://alistapart.com/article/creating-intrinsic-ratios-for-video
In order to use percentage(%), you must define the % of its parent element. If you use body{height: 100%} it will not work because its parent have no percentage in height. In that case in order to work that body height you must add this in html{height:100%}
In other cases to get rid of that defining parent percentage you can use
body{height:100vh}
vh stands for viewport height
You can use 100vw / 100vh. CSS3 gives us viewport-relative units. 100vw means 100% of the viewport width. 100vh; 100% of the height.
<div style="display:flex; justify-content: space-between;background-color: lightyellow; width:100%; height:85vh">
<div style="width:70%; height: 100%; border: 2px dashed red"></div>
<div style="width:30%; height: 100%; border: 2px dashed red"></div>
</div>
Sometimes, you may want to conditionally set the height of a div, such as when the entire content is less than the height of the screen. Setting all parent elements to 100% will cut off content when it is longer than the screen size.
So, the way to get around this is to set the min-height:
Continue to let the parent elements automatically adjust their height
Then in your main div, subtract the pixel sizes of the header and footer div from 100vh (viewport units). In css, something like:
min-height: calc(100vh - 246px);
100vh is full length of the screen, minus the surrounding divs.
By setting min-height and not height, content longer than screen will continue to flow, instead of getting cut off.
With new CSS sizing properties you can get away with not setting exact height on parent. The new block-size and inline-size properties can be used like this:
<!DOCTYPE html>
<style>
#parent {
border: 1px dotted gray;
height: auto; /* auto values */
width: auto;
}
#wrapper {
background-color: violet;
writing-mode: vertical-lr;
block-size: 30%;
inline-size: 70%;
}
#child {
background-color: wheat;
writing-mode: horizontal-tb;
width: 30%; /* set to 100% if you don't want to expose wrapper */
height: 70%; /* none of the parent has exact height set */
}
</style>
<body>
<div id=parent>
<div id=wrapper>
<div id=child>Lorem ipsum dollar...</div>
Resize the browser window in full page mode. I think the values are relative to viewport height and width.
For more info refer: https://www.w3.org/TR/css-sizing-3/
Almost all browsers support it: https://caniuse.com/?search=inline-size

How do I get the padding to scale in a scaling transform?

I am doing a scaling transform. The scaling origin is centered horizontally. When I scale the element, the vertical padding seems to be scaled, but the horizontal padding is not scaled. How do I get the horizontal padding to scale as well?
.inner {
margin: 0 auto;
width: 300px;
height: 300px;
background-color: #f99;
transform: scale(1.5);
transform-origin: top center;
box-sizing: border-box;
padding: 20px;
}
.inner2 {
background-color: #99f;
height: 260px;
}
.outer {
background-color: #ccc;
}
<div class="outer">
<div class="inner">
<div class="inner2">
</div>
</div>
</div>
Another question is with Chrome dev tools. The Chrome dev tools is not reflecting the changed computed properties after the scaling transform. (for example, the width is still unchanged in inspector).
Another question that I have is the inner element extends beyond the outer element. How do I get the outer element to contain the inner element after scaling transform?
UPDATE: I accidentally added a border to the inner element. After noticing the answer from #Stickers, I removed the border. Now, it is easy to observe that the horizontal padding is not scaled whereas the vertical padding seems to be scaled.
UPDATE: A codepen with a much larger padding showing that vertical padding is scaled whereas horizontal padding is not.
The .inner element has box-sizing: border-box; set, that tells the browser to account for any border and padding in the values you specify for width and height.
If we do the calculation 300-20x2-2x2=256 (height-paddingx2-borderx2), so that .inner2 should have height: 256px rather height: 260px; if you want to fit in perfectly. All padding values will be scaled correctly once you get that fixed.
For the size of the .outer elements, read the spec:
3. The Transform Rendering Model
Note: Transformations do affect the visual rendering, but have no affect on the CSS layout other than affecting overflow...
I think that also answers the DevTools question.

Max-height on border-boxed div with padding is not set

We use the percentage trick on paddings to keep aspect ratio to a div when the user scales his window. Like this:
.div {
background: red;
width: 80%;
margin: 0 auto 10px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding-bottom: 20%;
}
Now we would like to be able to set a maximum height to this div. Because the height of the div is determined by the padding on the div we would need the div to be border-boxed. So far so good. When trying to use a min-height on the div, this works. The max-height on this div however does not work for some reason.
.div {
max-height: 60px;
}
I created a fiddle to show you what i mean: http://jsfiddle.net/UxuEB/3/.
Tested this on Chrome, FF and IE. Can somebody tell me what I'm doing wrong or why this doesn't work as expected?
I realize this answer comes incredibly late to the party but I was trying to solve this exact same thing today and this question is the first result in Google. I ended up solving it with the below code so hopefully that will help someone out in the future.
First, add an extra inner div:
<div class="control control-max-height">
<div class="control-max-height-inner">
Max-height
</div>
</div>
And set the padding on that while hiding the overflow on the outer div:
.control {
background: red;
width: 80%;
margin: 0 auto 10px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.control-max-height {
max-height: 120px;
overflow: hidden;
}
.control-max-height-inner {
padding-bottom: 20%;
}
This obviously assumes you're fine with hiding part of the inner element when it overflows. In my case that wasn't a problem because the inner element is just an empty link element to make the whole thing clickable and the outer element just has a centered background image and a border set.
See fiddle: http://jsfiddle.net/UxuEB/7/
The property max-height works on the height of the element and you want to use it on the height and padding-bottom.
I think you are confused by the box-sizing property that it changes the element height to the overal height including the padding top and bottom (also me). But this is not the case as you will see in the jsFiddle example.
An example:
The element with content is 100px in height.
The max-height is set to 50px (element is now 50px in height).
Now we apply the padding-bottom of 100px (more then the height of the element). The padding of 100px is added to the total height of the element making it 150px.
JsFiddle example: clicky
Extending from Mike's answer, the same can be achieved with a single DOM element & a pseudo element, eg.
html:
<div class="le-div"></div>
css:
div.le-div {
max-height: 200px;
/* 👇 only necessary if applying any styles to the pseudo element
other than padding:
overflow: hidden;
*/
}
div.le-div::before {
content: '';
display: block;
padding-bottom: 60%;
}
Min-height property defines the height when height is solely dependent on padding only but max-height does not.
Not sure why but now in 2020, min and max css units does nice job as we need.
.classthatshoulddefineheight {
padding-bottom: min(20%, 60px);
}
So when 20% becomes greater than 60px then it will be limited to 60px (minimum of them).
The limitation to Mike's answer (and this Brad's answer - although Brad's technique can be incorporated to reduce the number of levels of containers) is that it requires overflow: hidden - which in my use-case (and in many others) a significant limitation.
I've reworked his example to work without overflow: hidden; using an additional level and absolute positioning.
http://jsfiddle.net/2ksh56cr/2/
The trick is to add another container inside the inner box, make it absolute positioned and then add the max-height to that container as well:
.inner-inner {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
max-height: 120px;
}
As long as your fine with having some additional DOM-elements, this should work in all scenarios for more or less all browsers.
Try display: flow-root; on the parent container.

CSS 100% height with padding/margin

With HTML/CSS, how can I make an element that has a width and/or height that is 100% of it's parent element and still has proper padding or margins?
By "proper" I mean that if my parent element is 200px tall and I specify height = 100% with padding = 5px I would expect that I should get a 190px high element with border = 5px on all sides, nicely centered in the parent element.
Now, I know that that's not how the standard box model specifies it should work (although I'd like to know why, exactly...), so the obvious answer doesn't work:
#myDiv {
width: 100%
height: 100%;
padding: 5px;
}
But it would seem to me that there must be SOME way of reliably producing this effect for a parent of arbitrary size. Does anyone know of a way of accomplishing this (seemingly simple) task?
Oh, and for the record I'm not terribly interested in IE compatibility so that should (hopefully) make things a bit easier.
EDIT: Since an example was asked for, here's the simplest one I can think of:
<html style="height: 100%">
<body style="height: 100%">
<div style="background-color: black; height: 100%; padding: 25px"></div>
</body>
</html>
The challenge is then to get the black box to show up with a 25 pixel padding on all edges without the page growing big enough to require scrollbars.
I learned how to do these sort of things reading "PRO HTML and CSS Design Patterns". The display:block is the default display value for the div, but I like to make it explicit. The container has to be the right type; position attribute is fixed, relative, or absolute.
.stretchedToMargin {
display: block;
position:absolute;
height:auto;
bottom:0;
top:0;
left:0;
right:0;
margin-top:20px;
margin-bottom:20px;
margin-right:80px;
margin-left:80px;
background-color: green;
}
<div class="stretchedToMargin">
Hello, world
</div>
Fiddle by Nooshu's comment
There is a new property in CSS3 that you can use to change the way the box model calculates width/height, it's called box-sizing.
By setting this property with the value "border-box" it makes whichever element you apply it to not stretch when you add a padding or border. If you define something with 100px width, and 10px padding, it will still be 100px wide.
box-sizing: border-box;
See here for browser support. It does not work for IE7 and lower, however, I believe that Dean Edward's IE7.js adds support for it. Enjoy :)
The solution is to NOT use height and width at all! Attach the inner box using top, left, right, bottom and then add margin.
.box {margin:8px; position:absolute; top:0; left:0; right:0; bottom:0}
<div class="box" style="background:black">
<div class="box" style="background:green">
<div class="box" style="background:lightblue">
This will show three nested boxes. Try resizing browser to see they remain nested properly.
</div>
</div>
</div>
The better way is with the calc() property. So, your case would look like:
#myDiv {
width: calc(100% - 10px);
height: calc(100% - 10px);
padding: 5px;
}
Simple, clean, no workarounds. Just make sure you don't forget the space between the values and the operator (eg (100%-5px) that will break the syntax. Enjoy!
According the w3c spec height refers to the height of the viewable area e.g. on a 1280x1024 pixel resolution monitor 100% height = 1024 pixels.
min-height refers to the total height of the page including content so on a page where the content is bigger than 1024px min-height:100% will stretch to include all of the content.
The other problem then is that padding and border are added to the height and width in most modern browsers except ie6(ie6 is actually quite logical but does not conform to the spec). This is called the box model. So if you specify
min-height: 100%;
padding: 5px;
It will actually give you 100% + 5px + 5px for the height. To get around this you need a wrapper container.
<style>
.FullHeight {
height: auto !important; /* ie 6 will ignore this */
height: 100%; /* ie 6 will use this instead of min-height */
min-height: 100%; /* ie 6 will ignore this */
}
.Padded {
padding: 5px;
}
</style>
<div class="FullHeight">
<div class="Padded">
Hello i am padded.
</div
</div>
1. Full height with padding
body {
margin: 0;
}
.container {
min-height: 100vh;
padding: 50px;
box-sizing: border-box;
background: silver;
}
<div class="container">Hello world.</div>
2. Full height with margin
body {
margin: 0;
}
.container {
min-height: calc(100vh - 100px);
margin: 50px;
background: silver;
}
<div class="container">Hello world.</div>
3. Full height with border
body {
margin: 0;
}
.container {
min-height: 100vh;
border: 50px solid pink;
box-sizing: border-box;
background: silver;
}
<div class="container">Hello world.</div>
This is one of the outright idiocies of CSS - I have yet to understand the reasoning (if someone knows, pls. explain).
100% means 100% of the container height - to which any margins, borders and padding are added. So it is effectively impossible to get a container which fills it's parent and which has a margin, border, or padding.
Note also, setting height is notoriously inconsistent between browsers, too.
Another thing I've learned since I posted this is that the percentage is relative the container's length, that is, it's width, making a percentage even more worthless for height.
Nowadays, the vh and vw viewport units are more useful, but still not especially useful for anything other than the top-level containers.
Another solution is to use display:table which has a different box model behaviour.
You can set a height and width to the parent and add padding without expanding it. The child has 100% height and width minus the paddings.
JSBIN
Another option would be to use box-sizing propperty. Only problem with both would be they dont work in IE7.
Another solution: You can use percentage units for margins as well as sizes. For example:
.fullWidthPlusMargin {
width: 98%;
margin: 1%;
}
The main issue here is that the margins will increase/decrease slightly with the size of the parent element. Presumably the functionality you would prefer is for the margins to stay constant and the child element to grow/shrink to fill changes in spacing. So, depending on how tight you need your display to be, that could be problematic. (I'd also go for a smaller margin, like 0.3%).
A solution with flexbox (working on IE11): (or view on jsfiddle)
<html>
<style>
html, body {
height: 100%; /* fix for IE11, not needed for chrome/ff */
margin: 0; /* CSS-reset for chrome */
}
</style>
<body style="display: flex;">
<div style="background-color: black; flex: 1; margin: 25px;"></div>
</body>
</html>
(The CSS-reset is not necessarily important for the actual problem.)
The important part is flex: 1 (In combination with display: flex at the parent). Funnily enough, the most plausible explanation I know for how the Flex property works comes from a react-native documentation, so I refer to it anyway:
(...) flex: 1, which tells a component to fill all available space, shared evenly amongst other components with the same parent
To add -webkit and -moz would be more appropriate
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
Frank's example confused me a bit - it didn't work in my case because I didn't understand positioning well enough yet. It's important to note that the parent container element needs to have a non-static position (he mentioned this but I overlooked it, and it wasn't in his example).
Here's an example where the child - given padding and a border - uses absolute positioning to fill the parent 100%. The parent uses relative positioning in order to provide a point of reference for the child's position while remaining in the normal flow - the next element "more-content" is not affected:
#box {
position: relative;
height: 300px;
width: 600px;
}
#box p {
position: absolute;
border-style: dashed;
padding: 1em;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
<div id="box">
<p>100% height and width!</p>
</div>
<div id="more-content">
</div>
A useful link for quickly learning CSS positioning
This is the default behavior of display: block The fastest way that you can fix it in 2020 is to set display: 'flex' of parent element and padding e.g. 20px then all its children will have 100% height relative to its height.
Border around div, rather than page body margin
Another solution - I just wanted a simple border around the edge of my page, and I wanted 100% height when the content was smaller than that.
Border-box didn't work, and the fixed positioning seemed wrong for such a simple need.
I ended up adding a border to my container, instead of relying on the margin of the body of the page - it looks like this :
body, html {
height: 100%;
margin: 0;
}
.container {
width: 100%;
min-height: 100%;
border: 8px solid #564333;
}
<style type="text/css">
.stretchedToMargin {
position:absolute;
width:100%;
height:100%;
}
</style>

Resources