Relative padding and vh units - bug or spec misunderstanding? - css

DEMO
Sometimes I'll create a square (or any rectangle, really) that will respect its ratio at any size using a method similar to this method.
What I want:
to prevent the square extending outside of the viewport on devices with a small height
i.e. mobile phone in landscape
Proposed solution
limit width of square to a percentage of viewport height using max-width: 90vh
expect ratio to be respected
CSS
.square {
position: relative;
height: 0;
padding-bottom: 100%;
overflow: hidden;
}
.square-inner {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.mw { max-width: 90vh;} /* solution, but makes things break */
HTML
<div class="square mw">
<div class="square-inner"></div>
</div>
What should happen
in viewports with small heights, the square should be a max width of 90% of the viewport height
What actually happens:
when viewport height is less than width of square:
width is constrained as per vh value
height is calculated from width of square had it not been constrained to vh
we get a vertically long rectangle
The spec says that the relative value is calculated from the 'containing block', which to me seems as though it should be the current width of the container.
Browser behaviour:
Chrome 29.0.1547.65: as described
Firefox 23.01: as described
Opera: does not respect vh at all Not validated with Opera 16+
Am I interpreting the spec incorrectly, or is this a possible bug in implementation by browser vendors?

The problem is in using both lengths in % and vh.
Try this:
Working Example
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
font-family: sans-serif;
font-weight: 100;
}
.neat {
width: 50%;
max-width: 600px;
min-width: 320px;
margin: 0 auto;
}
.col {
float: left;
padding: 2rem;
width: 90vh; /*** Important bit changed width:50%; to width:90vh; ***/
max-width: 50%; /*** Important bit added max-width:50%; ***/
}
.square {
position: relative;
height: 0;
padding-bottom: 100%;
overflow: hidden;
}
.square-inner {
position: absolute;
background-color: #333333;
color: white;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 1.5rem;
}
.mw {
max-width: 90vh;
}

I don't think Opera supports vh,and there are known issues. I'm wondering if this bug is affecting what you're seeing: http://code.google.com/p/chromium/issues/detail?id=124331.

Related

Prevent 100vw from creating horizontal scroll in pseudo

some times in wrapped by width div needs to set for an element background to full width, so I set it in an pseudo element, but descktop browser, when page is long height adds 16px for vertical scrooll bar to viewport, so I calculate it
by calc (see below).
Here is Example
HTML:
<div class="wrapped">
<h1>100vw background in wrapped</h1>
<div class="fullbg">
some body text, images, etc here
</div>
</div>
CSS
html, body { margin: 0; padding: 0; }
body { height: 100%; width: 100%; }
div { position: relative; }
*,*:before,*:after { box-sizing: border-box;
-moz-box-sizing: border-box; -webkit-box-sizing: border-box;
}
.wrapped {
width: 70%;
margin: 0 auto;
height: 150vh; /* simulate long heigh */
}
.fullbg {
height: 5em;
/* some styles here*/
}
.fullbg:before {
content: "";
bottom: 0;
display: block;
background: rgba(85, 144, 169, 0.7);
position: absolute;
width: 100vw;
right: 50%;
margin-right: -50vw; /* work for short page or mobile browser*/
margin-right: calc( -50vw + 8px ); /* work for desctop long page */
top: 0;
z-index: -1;
}
I looked answer at
Prevent 100vw from creating horizontal scroll
Difference between Width:100% and width:100vw?
and others questions,
but do not find real true universal css solution for this
as a temporary solution may be an js, like this:
var scrollbarWidth = ($(document).width() - window.innerWidth);
but I think it not the best solution, and now I not figured out how to use it with a pseudo considering that to scroll width can vary.
ps. no one overflow: hidden!
The scrollbar can be targeted specifically.
Check this out for the fix in chrome and safari
http://codepen.io/anon/pen/dXgmbZ
Key CSS:
.element::-webkit-scrollbar {
width: 0 !important;
}`
The codepen is just your example with the chrome fix. If you'd like to see a more robust solution, check out this JSFiddle:
http://jsfiddle.net/E78q3/
The idea behind this is just clipping out the scroll bar with absolute positioning and hiding container/wrapper overflow. Simple, clever, yet effective.
Further Reading:
https://blogs.msdn.microsoft.com/kurlak/2013/11/03/hiding-vertical-scrollbars-with-pure-css-in-chrome-ie-6-firefox-opera-and-safari/

Scaling a 1% width div up 100 times doesn't cover the full width of the parent

I'm trying to make a progress bar.
You'd think that a div with a width of 1% scaled up horizontally 100 times would span the width of its parent, but it doesn't. The amount of space left seams to depend on my window size, so I think this might be a rounding issue in the browser. Is there anything I can do to make this work?
I'm changing the progress of this bar quite often, so I don't want to change the bar's width property every time, as that would cause performance issues.
body {
margin: 0;
padding: 0;
}
#container {
background-color: red;
position: fixed;
left: 0;
right: 0;
top: 0;
padding: 0;
margin: 0;
height: 100px;
}
#progress {
position: absolute;
left: 0;
top: : 0;
width: 1%;
height: 100%;
background-color: yellow;
transform: scale(100, 1);
transform-origin: left top;
}
<div id="container">
<div id="progress">
</div>
</div>
I also made a codepen to demonstrate this issue: http://codepen.io/bigblind/pen/Zbozjv
The amount of space left seams to depend on my window size, so I think
this might be a rounding issue in the browser.
Yes. It is.
I don't want to change the bar's width property every time
I am not trying to debate the performance thingy here, but just trying to concentrate on the problem that if not width then what property could be used?
Well, you could just turn your progress on its head. Instead of the #progress div expanding to show the amount of progress, slide it out of the way to reveal the background #container div to show the amount of progress. Use the translate to slide the progress away.
In the demo below, hover to see the transform in effect.
Demo Fiddle: http://jsfiddle.net/abhitalks/y2o7yub9/1
Demo Snippet:
* { box-sizing: border-box; padding: 0; margin: 0; }
html, body { width: 100%; }
#container{
background-color: yellow; position: fixed;
left: 0; right: 0; top: 0;
height: 100px; width: 100%;
overflow: hidden; white-space: nowrap;
}
#progress{
position: absolute; left: 0; top: 0;
width: 100%; height: 100%;
background-color: red;
transform: translateX(0%); transition: transform 0.5s;
}
#container:hover > div { transform: translateX(100%); }
<div id="container">
<div id="progress"></div>
</div>
Problem
Looks to me that there is a rounding issue.
On a 1920 pixel monitor, 1% gets translated to 19.188 pixels which gets rounded down to 19 pixels
19 pixels * 100 = 1900 pixels which leaves a 20 pixel gap.
More information here: http://ejohn.org/blog/sub-pixel-problems-in-css/
Edit: if you rescale your browser, on some widths, the red part is larger, smaller or gone; which confirms the rounding issue.
Solution
Declare a progress bar with a fixed width : 200px
Initialise it to 2px which can't be rounded up/down

H1 larger than viewport - how?

Trying to make an H1 larger than the viewport so it partially sits hidden off the screen horizontally without prompting x-axis scroll. The body and container width is set to 100% so currently the H1 just breaks to the next line when it gets wider than the viewport. Any idea's?
This was my interpretation of your question, the use of vh units makes the font-size size to the viewport.:
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#biggee {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: hidden;
font-size: 50vh;
line-height: 15vh;
white-space: nowrap;
}
<div id="biggee">
<h1>This is HUGE</h1>
</div>
A possible solution is to set a height equal to a single line of your h1 on the container.
Example:
.container {
width: 100%;
overflow:hidden;
height: 690px;
}
Fiddle: http://jsfiddle.net/7pyxtjah/
So if a single line of your h1 is 60px in height, make the height 60px.
One way (of presumably, many) is:
h1 {
/* width of the parent element: */
width: 100%;
/* not particularly relevant */
padding: 0;
margin: 0;
/* large font-size to increase the chance of the text
extending out of the view-port: */
font-size: 600%;
/* again, to increase the chance of the text exceeding
the view-port: */
letter-spacing: 400%;
/* to prevent scroll-bars: */
overflow: hidden;
/* preventing line-breaks, to stop wrapping: */
white-space: nowrap;
}
<h1>This is the header</h1>
Unless you meant, literally, to have the <h1> element larger than the view-port, in which case:
html, body {
margin: 0;
padding: 0;
/* to prevent the user scrolling to see the extent of the text
'below the fold': */
overflow-y: hidden;
}
h1 {
/* vh: 1% of the viewport's height,
this sets font-size to 150% of the viewport's height: */
font-size: 150vh;
line-height: 1.4;
margin: 0;
padding: 0;
overflow: hidden;
white-space: nowrap;
}
<h1>This is the header</h1>
References:
CSS relative lengths and units (including vh/vw).

Position Absolute and Bottom 0

http://cdpn.io/FykHr
I seem to have an issue with the combined CSS properties:
position: absolute;
bottom: 0;
First you can see that the .footer div doesn't isn't at the bottom. Now, change the font-size from 120px to 50px and the div seems to be working the way I inteded it to.
How do I make the .footer div stay at the bottom (not fixed at the bottom of the screen) regardless of the size of the .content div.
You need to add position: relative; to the parent container, which in this case is .wrapper.
Here's a good reference page on absolute positioning.
There is one way to do that:
body {
height: 100%;
margin: 0;
}
html {
padding-bottom: 50px;
min-height: 100%;
box-sizing: border-box;
-moz-box-sizing: border-box;
position: relative;
}
footer {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 50px;
background-color: red;
}
http://jsfiddle.net/n8UNM/
There is still one limitation. You have to know height of footer and set it in two places.

CSS fixed div max height in IE?

I have a fixed div setup using this:
.box {
position: fixed;
width: 600px;
bottom: 20px;
left: 50%;
max-height: 400;
overflow:auto;
}
The problem I have is that on internet explorer it ignores the max-height, the div just expands upwards and out of view with no scroll bars, even if I set overflow: scroll;.
BTW I am using the hack to do fixed absolute position boxes so they stay on the screen reguardless of scrolling, if that matters:
* { margin: 0; }
* html .box { position: absolute; }
try this:
* html .box{
height: expression( this.scrollHeight > 399 ? "400px" : "auto" ); /* fix for ie 5+ */
}
.box {
max-height: 400px;
position: fixed;
width: 600px;
bottom: 20px;
left: 50%;
overflow:auto;
}

Resources