Off by one pixel issue in IE CSS transform - css

I am using transform: skew to create the effect of a down arrow on my banner image using both the :before and :after tags. The result should look like the following:
However, in IE 9-11 there seems to be a rounding issue. At some heights there is one pixel from the background image that shows below the skewed blocks resulting in the following:
In my case, the banner is a percentage of the total height of the window. Here is the some sample code which should be able to reproduce the problem:
HTML
<div id="main">
<div id="banner"></div>
<section>
<h1>...</h1>
<p>...</p>
</section>
</div>
CSS
#banner {
position: relative;
background-color: green;
width: 100%;
height: 75%;
overflow: hidden;
}
#banner:before,
#banner:after {
content: '';
display: block;
position: absolute;
bottom: 0;
width: 50%;
height: 1.5em;
background-color: #FFFFF9;
transform: skew(45deg);
transform-origin: right bottom;
}
#banner:after {
right: 0;
transform: skew(-45deg);
transform-origin: left bottom;
}
body {
background-color: #333;
position: absolute;
width: 100%;
height: 100%;
}
#main {
max-width: 40em;
margin: 0 auto;
background-color: #FFFFF9;
position: relative;
height: 100%;
}
section {
padding: 0 1em 5em;
background-color: #FFFFF9;
}
And here a working example.

Yes, seems to be a rounding issue – and I don’t know of anything that one could do to fix this. It’s in the nature of percentage values that they don’t always result in full pixel values – and how rounding is done in those cases is up to the browser vendor, I’m afraid.
I can only offer you a possible workaround (resp. “cover up”) that seems to work – if the layout really is as simple as this, and the main content area has a white background, and no transparency or background-image gets involved there.
Pull the section “up” over the banner by a negative margin of -1px (eliminated top margin of h1 here as well, otherwise it adjoins with the top margin of the section – countered by a padding-top), so that its background simply covers up that little glitch:
section {
padding: 1em 1em 5em;
background-color: #FFFFF9;
position:relative;
margin-top:-1px;
}
section h1:first-child { margin-top:0; }
Well, if you look closely, that makes the corner of triangle look slightly “cut off” (by one pixel) in those situations where the rounding glitch occurs – if you can live with that (and your desired layout allows for it), then take it :-) (And maybe serve it to IE only by some means). If not – then sorry, can’t help you there.

Related

content: url() not working in firefox, ::before/::after not fixing it [duplicate]

This question already has answers here:
Can you apply a width to a :before/:after pseudo-element (content:url(image))?
(3 answers)
Closed 5 years ago.
I've started learning HTML/CSS but ran into a problem that has been discussed sometimes around here, but the solutions don't seem to fix my problem, so I'm wondering what I am doing wrong.
I want to use content: url() in CSS, specially because I want some images to change on :hover.
After searching for this problem, the solution mentioned here and on other threads (include :before), makes the image appear, but completely ignores the height/width set, effectively showing the image, but with its original size.
Have also tried changing it to "background-image: url ()" but the problem remains. Why aren't the height/width being accepted? I'm clueless here.
<div id="logo"></div>
CSS:
#logo {
content: url(images/asspreto.png);
height: 90px;
width: 168px; /*only had height set, but tried to put width as well to see if it worked. It doesn't */
float: right;
vertical-align: middle;
}
#logo:hover {
content:url(images/assazul.png);
cursor: pointer;
}
If you want an image to fit in the available space, you need to indicate so. You can do this using the background-size directive. To make it so that the image fits in the available space, but keeps its aspect ratio, use contain.
Here is an example. You can see how the image is scaled and does not fill the entire element.
#logo {
width: 400px;
height: 300px;
background-image: url('https://placehold.it/500?text=500x500, but scaled');
background-position: center;
background-repeat: no-repeat;
background-size: contain;
border: 1px solid #000;
}
<div id="logo"></div>
Here is my interpretation: you can't change the dimensions of the media supplied to the render via content: url(). It's not mentioned in the specs though, but you can see that setting dimensions simply won't work when placing media with the help of pseudo elements.
I myself experimented a bit on this and this is what I come up with: http://codepen.io/rahul_arora/pen/GWvNgJ
You simple can't resize the media inserted using pseudo elements with height, width, object-fit, etc. It will take its space and only the overflow can help you to hide its overflowing.
If you really want to get this done with the help of pseudo elements only, an alternative way to do that is by using the image as a background.
.logo {
position: relative;
height: 90px;
width: 168px;
}
.logo:after {
position: absolute;
top: 0;
left: 0;
content: "";
background: url(https://unsplash.it/g/200/200?image=1062) 0 0 no-repeat / cover;
height: 100%;
width: 100%;
}
.logo:hover:after {
background-image: url(https://unsplash.it/200/200?image=1062);
}
<div class="logo"></div>
I hope that solved it for you. Cheers!
#logo:before {
background: url("https://www.gravatar.com/avatar/732637806aee1bf98e7ef1f3658db84a?s=328&d=identicon&r=PG&f=1")no-repeat;
height: 200px;
width: 100%; /*only had height set, but tried to put width as well to see if it worked. It doesn't */
float: right;
vertical-align: middle;
content:"";
height:300px;
width:300px;
position:absolute;
top:0;
left:0;
}
#logo{position:relative;}
<div id="logo"></div>

Absolute positioning error in Internet Explorer 11

I have a page that displays correctly in Google Chrome, Firefox, and Opera, but has an error in Internet Explorer 11.
Here is the HTML, with the unnecessary parts stripped out:
<div class="container">
<div class="page-content">
<div id="corner"></div>
... page contents here
</div>
</div>
And here is the CSS:
.container {
margin: 0;
min-height: 100%;
padding: 0;
}
.page-content::after {
content: "";
display: block;
height: 1px;
}
.page-content {
background: linear-gradient(137deg, transparent 121px, #ffffff 20px) repeat scroll 0 0 rgba(0, 0, 0, 0);
margin: 190px 100px 150px;
max-width: 64em;
padding: 10px 120px 145px;
z-index: 2;
}
.page-content {
margin: auto;
max-width: 64em;
padding: 0 1em 1em;
}
#corner {
background-color: #ffffff;
background-image: url("corner.png");
display: block;
height: 200px;
left: 120px;
position: absolute;
top: 20px;
width: 200px;
z-index: -1;
}
As you can see in this screenshot the #corner element is not positioned correctly.
I'm really not sure what to try, since this is specific to Internet Explorer. Been trying different things with the code over the past couple of hours with no luck so far.
try adding position:relative to the containing elements of div#corner, .container and/or .page-content
position:relative on a containing element sets the bounds of an absolutely positioned element equal to the parent element, rather than the whole page.
so a value of left:0px isn't equal to the top left side of the page, but the left side of the parent element.
It is somewhat surprising this only occurs in ie11 though as its a pretty straightforward issue which makes me suspect that there could easily be a secondary solution, but then again, having had to support IE since ~ie6 I guess I'm not really all that surprised if its just IE sucking.
Side note: Not sure if this is what you're trying to do, but min-height:100% does not make content's size to 100% the height of the screen.
Replace that with this:
position:absolute;
top:0;
bottom:0;
left:0;
right:0;
Anyway, you've set #corner to
position: absolute;
top: 20px;
left: 120px;
And that's where IE is placing it, relative to the entire page. It's doing what you're telling it to do. With the other browsers, it's position is absolute compared to that header. But to take a guess, you probably wanted to set it to position: relative.
Just in case this helps someone else:
I had a similar issue. It looked like ie11 was ignoring the 'right' property:
right: -320px;
but it turned out to be because I had set the 'left' property to:
left: initial;
Turns out the 'initial' keyword is unsupported by ie11:
left: initial doesn't work in internet explorer

Why CSS3 is not supporting vertical center (directly)?

One very common question on CSS is how to vertically center an element. With CSS3 being able to do so many special effect, why they are not including the vertically center function into CSS3?
I don't believe it is a difficult function to add if even a beginner developer can make a function to center things with javascript. And with so many hacks for different situations, it is clear that with CSS alone it is possible to center things vertically. So maybe there are other reasons that they decide not to make it a standard property?
That is because how layout is performed with CSS — CSS is predominantly arranging items on the x-axis, like how 100% width works as expected but not 100% height. This is likely due to the possible "calculation/logic loop" that happens as width is dependent on height and vice versa, so one axis must always be prioritized when it comes to calculation.
Extra info by #BoltClock:
The x-axis thing has to do with the natural flow of text in a
document. Remember that the Web started off as a series of pages, so
HTML and CSS were originally built around this fundamental premise -
it has since evolved into an application platform, but the legacy is
still there. Flexbox is the CSS3 way to vertically center boxes - the
only issue is cross-browser support, but since the question is about
CSS3 anyway, that's to be expected.
Similarly, in terms of dictating alignment, horizontal alignment is easy because the width of an element is often implicitly or explicitly stated, like how a block element automatically has a implicit width of 100% unless otherwise stated, allowing for easy calculation of a center position along the horizontal axis.
However, this does not work for the case of vertical alignment, where often than not the vertical dimension is dependent on the amount, length and size of the content. In the case where vertical height is explicitly stated, this can actually be easily done:
by using the CSS flexbox method
The good: standards compliant and very simple, dimension of element of interest does not have to be fixed
The bad: lack of extensive cross-browser support, but appears very promising today
body {
margin: 0;
padding: 0;
}
.box {
background-color: #eee;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100vh;
}
.box > .content {
background-color: #333;
color: #eee;
padding: 1em 2em;
}
<div class="box">
<div class="content">I am centered</div>
</div>
by using absolute positioning and CSS transforms
The good: extensive cross-browser support, dimension of element of interest does not have to be fixed
The bad: fuzzy text rendering (occasionally) due to sub-pixel translation
body {
margin: 0;
padding: 0;
}
.box {
background-color: #eee;
position: relatve;
width: 100%;
height: 100vh;
}
.box > .content {
background-color: #333;
color: #eee;
padding: 1em 2em;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
<div class="box">
<div class="content">I am centered</div>
</div>
by using absolute positioning and negative margins
The good: extremely straightforward
The bad: dimension of element of interest MUST be fixed
body {
margin: 0;
padding: 0;
}
.box {
background-color: #eee;
position: relative;
width: 100%;
height: 100vh;
}
.box > .content {
background-color: #333;
color: #eee;
width: 200px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -100px;
}
<div class="box">
<div class="content">I am centered</div>
</div>

What are the calculations behind the properties in a re-rotated element?

I have been playing around with an idea of a contact card type of thing. Apparently hexagons are quite a new trend, but I'd like to keep it a tad simpler, namely: rotated squares. Considering I am quite knowledgeable with HTML and CSS, it wasn't that hard to accomplish this. In a few minutes I came up with this.
HTML
<a href="#" title="Profile of Banana">
<span style="background-image: url(http://s5.favim.com/orig/52/portrait-sigma-50mm-f1.4-hsm-canon-eos-5d-mk2-face-Favim.com-473053.jpg);">
Queen Elizabeth
</span>
</a>
CSS
a {
display: inline-block;
margin: 50px;
width: 150px;
height: 150px;
transform: rotate(45deg);
position: relative;
overflow: hidden;
}
/* Pseudo element for border */
a:after {
content: "";
display: block;
width: 142px;
width: calc(100% - 8px);
height: 142px;
height: calc(100% - 8px);
border: 2px solid white;
position: relative;
z-index: 10;
top: 4px;
left: 4px;
}
/* Span for bg-image and text */
a > span {
display: block;
height: 213px;
width: 213px;
top: -31px;
left: -31px;
position: absolute;
background-size: cover;
background-position: center;
transform: rotate(-45deg);
padding: 76px 24px 0;
}
The idea is quite simple:
Make the link itself a block element, rotated it 45 degrees. Don't forget overflow: hidden
Rotate its child 45 degrees back, apply a background-image to this element (dynamically loaded in my case, therefore inline)
This works in all major browsers and degrades gracefully into a simple square in other browsers (IE8 and below; though you might need a background size polyfill). For this reason I want to keep this HTML structure.
So, what's the problem? First of all I'd like to make it applicable to different sizes where I would only need to set the width and height of the link itself (a) after which the height and width of its child are calculated automatically - in my project I can use the relatively new CSS3 calc() function, if that's of any help, along with the beauty of SASS/SCSS. In other words, I need the ratio between the width of a and its child span. As far as I can tell, it seems that the ratio is the square root of 2: 213 / 150 = 1.42. My first question is, then, why? What's the logic and/or arithmetic behind this? Why can't the span simply take up 100% width of its parent? Why need it be exactly square root 2 times more?
Additionally, I also would like to know where the top and left values come from. I haven't figured out yet which arithmetic might be the base of is. I do know that this might be dependent on the value of transform-origin, but I don't know how exactly. In other words, is it possible with a pre-defined transform-origin value to have top and left to be zero and by doing so removing the need for a per-case calculated value? If not, how can the value of these properties be calculated based on the width value of its parent, as that's the only value that should be known?
Summary, if only the width and height of a are known, how do I:
calculate the width for its child, and how can that be explained?
calculate/use the offsets (top and left) on span and how can they be explained?
I do not want to use any JS solutions for this. If something isn't clear, please post a comment so I can clarify.
UPDATED FIDDLE
First of all, as the background-image defined for span will overlap the actual a element, it needs to be bigger. As we are talking about an angle of 45 degrees, this leads to a triangular cut-off shape in which the size of the main square (i.e. the image) is the long side, and the other two equally-sized lines are of the anchor. Therefore, the size of the image (span) should be equal to sqrt(2)*100% ~= 141.42%.
The positioning of the span then. First we rotate the image back by 45 degrees. Import for this action is that the transform-origin is set to 0 0 rather than 50% 50%. By doing so, the element is rotated around a single point right in the top middle of the rhombus. After rotating it's only a matter of translate the element on the X-axis, which can also be done with CSS transforms: translateX(-50%).
No matter what value is now passed onto a's width and height, the image should always be aligned perfectly within it, with the correct dimensions.
(In the fiddle, try giving a a value of, say, 400px. It looks nice, doesn't it? You can also give nice hover effects to the image.)
a {
display: inline-block;
width: 200px;
height: 200px;
transform: rotate(45deg) translate(50%);
position: relative;
overflow: hidden;
}
a:after {
content: "";
display: block;
width: calc(100% - 8px);
height: calc(100% - 8px);
border: 2px solid white;
position: relative;
z-index: 10;
top: 4px;
left: 4px;
}
a > span {
display: block;
height: 141.42%;
width: 141.42%;
top: 0;
left: 0;
position: absolute;
background-size: cover;
background-position: center;
transform: rotate(-45deg) translateX(-50%);
transform-origin: 0 0;
}

CSS resize of image in fluid lightbox container

Short version: Make the image fit nicely the visible area for small windows, starting from this fiddle
Update: There doesn't seem to be a solution for this issue. I thought there might be one because Chrome actually makes it possible (see my answer) but behavior is different in other browsers.
Longer version:
I'm working on a lightweight fluid lightbox and have an apparently simple CSS issue I can't resolve.
I want the content (a single image) to be downsized if needed to fit, while keeping the aspect ratio the same.
Here's a demo fiddle: http://jsfiddle.net/3a9y9/2/ . Resize the window so the image doesn't fit height wise.
It almost works, but the height given to the image is slightly more than what's actually visible so a bit of the bottom gets clipped. I've tried tweaking things to no avail; I wish I understood how come the available height is too high.
Maybe it's related, but IE 9 doesn't even maintain the aspect ratio with this attempt of a solution. Also, Chrome behaves strangely when resizing the window and clicking on run in the fiddle will sometimes redraw differently.
What's the solution?
It's no problem to wrap the <img> in a <div> or two if it's necessary, but the top-level structure should ideally remain the same (i.e. a .featherlight-content inside a .featherlight and that's it).
In featherlight.min.css, change .featherlight-image{width: 100%} to .featherlight-image{max-width: 100%}
and at the end, write the following css:
#media only screen and (min-height:1000px) {
.featherlight-image { height: 900px; }
}
#media only screen and (min-height:700px) {
.featherlight-image { height: 600px; }
}
#media only screen and (max-height:700px) {
.featherlight-image { height: 400px; }
}
What it's doing is changing the width of the lightbox from fixed 100% into a maximum of 100% (so that it's adjusted as per height). And then with #media, the height of the image is restricted. #media will allow for responsiveness based on browser height.
Higher resolution browsers will show the image at 900px height; those with a minimum of 700px height will show it at 600px, and smaller ones will show it at 400px.
You can of course adjust the numbers as per your preference; but this solution worked and solves the problem of long images.
Here's a jsfiddle. Note that using data-featherlight="image" is important for this to work properly.
Hope it helps.
In my opinion, the easiest way to both fit an image in the container and to center it is absolute positioning with margin: auto:
.featherlight img {
max-width:90%;
max-height:90%;
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
}
(Fiddle)
Alternatively, you can try to set the size of the image in viewport relative units (vw/vh), they have quite good browser support now: http://caniuse.com/#search=vw
Note: The following appears to be true only for Chrome, but it doesn't work in Firefox or IE...
After much twiddling around, my conclusion is that there's a fundamental difference in the way that height and width are treated in general and that it affects calculations here.
It's bound to be related to the flow of things, like how reducing the width of a <div> will have the content flow down, expanding the height, but how reducing the height of a <div> won't make it wider.
The clipping here is due to the fact that the border-bottom and padding-top are not taken into account in the available height. The solution is thus to remove those altogether.
If one still wants a border, then it can be faked by adding an absolutely positioned <div>. Here's the corresponding fiddle.
It gets cut off because the padding is throwing it off.
It doesn't work in IE or Firefox because they don't assume that the height of content div should stretch to fit its container's height. You would have to use height: 100% or some other percentage. This causes more problems when trying to achieve a max-height.
It doesn't enlarge the image when the size gets larger in height because that is the way most browsers handle re-rendering the page (or not re-rendering in this case) when the size of the viewport changes in height. You will have to force a re-rendering of the page. The only CSS way I know how to do that is with a CSS3 animation.
Here is a solution that does not work in Firefox or IE (so... not that great of a solution), but it fixes the cutting-off and resizing issues.
http://jsfiddle.net/SombreErmine/ENrnu/5/
It utilizes calc() and CSS3 animations; so it's definitely limited in practical use. I'm not posting this as the solution. I'm mostly posting it to share some information on what I've learned. Hopefully, this will help lead to a real solution.
HTML Code:
<div class="featherlight" style="display: block;">
<div class="featherlight-content">
<img src="http://placekitten.com/640/480" alt="" class="featherlight-image featherlight-inner"/>
</div>
</div>
CSS Code:
.featherlight {
position:fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
text-align: center;
background: rgba(0, 0, 0, 0.8);
}
.featherlight:before {
/* position: trick to center content vertically */
content:'';
display: inline-block;
height: 100%;
vertical-align: middle;
margin-right: -0.25em;
}
.featherlight .featherlight-content {
padding: 25px;
position: relative;
text-align: center;
vertical-align: middle;
display: inline-block;
min-width: 30%;
margin-left: 5%;
margin-right: 5%;
max-height: 95%;
background: #fff;
}
.featherlight .featherlight-image {
max-width:100%;
max-height:calc(100% - 50px);
vertical-align: bottom;
-webkit-animation: render_update 1s linear 0s infinite;
-moz-animation: render_update 1s linear 0s infinite;
-o-animation: render_update 1s linear 0s infinite;
animation: render_update 1s linear 0s infinite;
}
#-webkit-keyframes render_update { from { padding-bottom: 0.001px; } to { padding-bottom: 0px; } }
#-moz-keyframes render_update { from { padding-bottom: 0.001px; } to { padding-bottom: 0px; } }
#-o-keyframes render_update { from { padding-bottom: 0.001px; } to { padding-bottom: 0px; } }
#keyframes render_update { from { padding-bottom: 0.001px; } to { padding-bottom: 0px; } }
You can try the following approach. Elements that have a set width become wider when they have padding and/or border-width. To avoid these problems, make use of the now common box-sizing: border-box; reset.
*,
*:before,
*:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
An element can be centered by setting height: 100%; to a "ghost" element (it can be a pseudo element) inside the parent and vertical-align: middle; to both.
.featherlight {
background-color: rgba(0, 0, 0, 0.8);
bottom: 0;
font-size: 0;
left: 0;
overflow: auto;
padding: 0 5%;
position: absolute;
right: 0;
text-align: center;
top: 0;
}
.featherlight:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
.featherlight-content {
display: inline-block;
margin: 5% 0;
max-width: 100%;
vertical-align: middle;
}
Images can be made responsive-friendly by applying max-width: 100%; and height: auto; to the image so that it scales nicely to the parent element.
.featherlight-content img {
border: 25px solid #fff;
display: block;
height: auto;
max-width: 100%;
}
See live example here: http://jsfiddle.net/cdog/AXzz8/.

Resources