Absolute positioning :after and transforming it not aligning it in center - html

Hey guys I had to create simple dots on a carousel like so:
And hence I used the following method:
.banner-nav-dots > li > a {
position: relative;
}
.banner-nav-dots > li.active > a:after {
content: '';
background: #6e2c91;
height: 5px;
width: 5px;
display: inline-block;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
-o-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);
border-radius: 50%;
}
Now that should have really centered the dot , but as can be seen on THIS LINK, they are not exactly aligning in the center. Why? Why are they not aligning in the center?
Below is a MVCE:
.circle {
position: relative;
box-sizing: border-box;
display: inline-block;
border: 2px solid #6e2c91;
border-radius: 50%;
height: 15px;
width: 15px;
}
.circle:after {
position: absolute;
content: '';
display: inline-block;
height: 5px;
width: 5px;
top: 50%;
left: 50%;
border-radius: 50%;
background: #6e2c91;
transform: translate(-50%, -50%);
}
<div class='circle odd-numbered'></div>
I am more interested in the WHY part. Can somebody explain please?
P.S. this absolute position method combined with transform has always worked for me, but just on this instance its caused this issue and I don't know why. Checked both in FF and Chrome.

The problem seems to be due to a combination of odd numbered dimensions for parent container (height: 15px, width: 15px) and the 50% value for positioning attributes on child (top: 50%, left: 50%). This means that the actual calculated value will be 5.5px ((15px - 4px) / 2) for left and top (15px - 4px due to box-sizing: border-box also being applied on the parent).
When such fractional values are encountered, it looks like the browsers round-off the value. I couldn't find anything about this in the specs (whether it should be a round-up or down) and there aren't many recent articles on the net also about this particular thing. However, I did manage to find this old article which says that each browser treats them differently. Some round it down whereas others round it up. Either ways, the child element is not going to at the exact center.
The fix for this case seems to be to set an even-numbered value for the parent's dimensions.
.circle {
position: relative;
box-sizing: border-box;
display: inline-block;
border: 2px solid #6e2c91;
border-radius: 50%;
}
.odd-numbered {
height: 15px;
width: 15px;
}
.even-numbered {
height: 16px;
width: 16px;
}
.circle:after {
position: absolute;
content: '';
display: inline-block;
height: 5px;
width: 5px;
top: 50%;
left: 50%;
border-radius: 50%;
background: #6e2c91;
transform: translate(-50%, -50%);
}
<h4>Odd Numbered Dimensions - PROBLEM </h4>
<div class='circle odd-numbered'></div>
<h4>Even Numbered Dimensions - NO PROBLEM </h4>
<div class='circle even-numbered'></div>

Related

Why does same size elements show different when zoom?

Here are two pseudo element before and after on same element. Both have 1px width. When I change the zoom of browser at some points it seems that their width is different.
.main::after,
.main::before {
content: "";
position: absolute;
height: 17px;
width: 1px;
background-color: orange;
top: 50%;
transform: translate(-50%, -50%);
}
.main::after {
left: 70%;
}
.main::before {
left: 30%;
}
.main{
position: relative;
padding:30px;
width: 12px;
}
<div class="main"></div>
You will be able to notice the issue by changing the browser zoom.
Yes, this is a well known phenomenon.
It comes about because the system is trying to match one CSS pixel onto a screen which uses several screen pixels to hold one CSS pixel.
This can lead to edge effects (sort of like rounding errors) when the user zooms in or out. At certain zoom levels it can match a whole number of pixels, but at others it has to decide whether to leave out (or include) some screen pixels.
If you make your bar have 2px (CSS) width then at least on my system while I do see the phenomenon at 90% and 110% zoom I don't see it on others.
.main::after,
.main::before {
content: "";
position: absolute;
height: 17px;
width: 2px;
background-color: orange;
top: 50%;
transform: translate(-50%, -50%);
}
.main::after {
left: 70%;
}
.main::before {
left: 30%;
}
.main{
position: relative;
padding:30px;
width: 12px;
}
<div class="main"></div>

Position fixed element is not apply max-width 100% of window's width

I have an element, of id "r-u-ok". It's a pop-up and its content can have different word counts.
I want to set only the max-width, not the fixed width. A fixed width can't self-adapt to the content's word count. Besides, I also hope to vertical align it in the middle and horizontal align it to the center.
But even when I set 100% to max-width attribute, its max-width still is not the width of window, though it contains many words.
WHY?
Ignore my poor English.
#r-u-ok {
position: fixed;
/* display: none; */
max-width: 70%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
z-index: 99;
background-color: rgba(0, 0, 0, .8);
color: #fff;
box-sizing: border-box;
padding: 20px;
text-align: center;
border-radius: 10px;
font-size: 16px;
}
<div id="r-u-ok">
I think it should 100% width of this window, if the word more enough.
</div>
Here is an example: fiddle link
I think due to the position fixed, the div cannot grow as it would in normal document flow. To get over this, use an extra div - the outer div to position and the inner div can then grow with it's content:
#r-u-ok {
position: fixed;
width:100%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
z-index: 99;
text-align:center;
}
#r-u-ok > div {
display: inline-block;
max-width: 100%;
background-color: rgba(0,0,0,.8);
color: #fff;
box-sizing: border-box;
padding: 20px;
text-align: center;
border-radius: 10px;
font-size: 16px;
}
<div id="r-u-ok">
<div>
I think it should 100% width of this window, if the word more enough.
</div>
</div>
Updated Fiddle
The problem is that with the left:50%, the system thinks you want to restrict the width to half of the window, even though you translate the whole thing by -50%.
So what you need to do is set the width explicitly. There is no other way. Otherwise you'd be stuck with this half.
Fortunately, width: 100% is not the only solution. What you can do is width: max-content, which does exactly what you need.
Unfortunately, it doesn't work in all browsers. IE and Edge will not comply. But most others will, if you provide the right prefixes.
#r-u-ok {
position: fixed;
/* display: none; */
max-width: 99%; /* changed */
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
z-index: 99;
background-color: rgba(0, 0, 0, .8);
color: #fff;
box-sizing: border-box;
padding: 20px;
text-align: center;
border-radius: 10px;
font-size: 16px;
/* added */
width:-webkit-max-content;
width:-moz-max-content;
width:max-content;
}
<div id="r-u-ok">
I think it should 100% width of this window, if the word more enough.
</div>
Just add width:100%
#r-u-ok {
position: fixed;
/* display: none; */
width: 100%;
max-width: 100%;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
z-index: 99;
background-color: rgba(0, 0, 0, .8);
color: #fff;
box-sizing: border-box;
padding: 20px;
text-align: center;
border-radius: 10px;
font-size: 16px;
}
i have a demand, the element, which id is "r-u-ok",is a pop, has a several possibility of content's word count.it's judge by a ajax request's callback data. and i want the element only has a max-width, not a fixed width.a fixed width can't self-adaption
the content's word count, besides i also hope it is vertical align middle and horizontal align center. but, even i set 100% to max-width attribute, it's max-width still not the width of window, though it's contain many word. WHY?
<div id="r-u-ok">
I think it should 100% width of this window, if the word more enough.
</div>
I assume you want to display this div in full width. In order to do that:
Remove
max-width: 70%;
Add
width: 100%;
OR
width: 100vw;

How to set ribbon on image by stacking it in a div?

I currently have an ng-repeat that looks like this:
<div class="repeaterDiv" data-ng-repeat="item in itemArray">
<div class="wrapper">
<img class="imageClass" ng-src="{{item.image}}"/>
<div class="corner-ribbon bottom-right sticky green shadow">Changed</div>
</div>
</div>
Here is the CSS pulled from this codePen:
.corner-ribbon{
width: 200px;
background: #e43;
position: absolute;
top: 25px;
left: -50px;
text-align: center;
line-height: 50px;
letter-spacing: 1px;
color: #f0f0f0;
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.corner-ribbon.sticky{
position: fixed;
}
.corner-ribbon.shadow{
box-shadow: 0 0 3px rgba(0,0,0,.3);
}
.corner-ribbon.bottom-right{
top: auto;
right: -50px;
bottom: 25px;
left: auto;
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.corner-ribbon.green{background: #2c7;}
I am trying to figure out how to get the ribbon to be restricted to the wrapper class. Does anyone know how I can do that? so I'm still using the same ribbon, but instead of being in the bottom right of the screen, it is at the bottom right of the image for which it applies?
you need to use relative/absolute position and reset display of .wrapper to shrink on image. Then add overflow:hidden to cut off edges of ribbon:
.corner-ribbon {
width: 200px;
background: #e43;
position: absolute;
top: 25px;
left: -50px;
text-align: center;
line-height: 50px;
letter-spacing: 1px;
color: #f0f0f0;
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.corner-ribbon.sticky {
position: absolute;
}
.corner-ribbon.shadow {
box-shadow: 0 0 3px rgba(0, 0, 0, .3);
}
.corner-ribbon.bottom-right {
top: auto;
right: -50px;
bottom: 30px;
left: auto;
transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
}
.corner-ribbon.green {
background: #2c7;
}
.wrapper {
position: relative;
display: table-cell;/* or inline-block or float */
overflow: hidden;
}
img {
display: block;
}
<div class="repeaterDiv" data-ng-repeat="item in itemArray">
<div class="wrapper">
<img class="imageClass" ng-src="{{item.image}}" src="http://lorempixel.com/300/200" />
<div class="corner-ribbon bottom-right sticky green shadow">Changed</div>
</div>
</div>
The class has fixed positioning.
.corner-ribbon.sticky{
position: fixed;
}
So for exact css you may not be able to attach ribbon to each img, rather ribbon would go to specific place in window only. However, you can adjust css a bit. Make wrapper class relative, and .corner-ribbon.sticky absolute position. Then adjust your css fot top/bottom/left/right properties to align them.
.wrapper{
position: relative;
}
.wrapper .corner-ribbon.sticky{
position: absolute;
/* put top/bottom/left/right values here*/
}

Full width overlapping triangles

I currently need to make something with CSS that would look like this:
I managed to do it with this:
.top {
position: relative;
}
.top .gray-bar {
position: absolute;
width: 100%;
height: 50px;
background-color: #cdcbcc;
-ms-transform: rotate(1.2deg);
transform: rotate(1.2deg);
margin-top: -25px;
z-index: 2;
}
.top .cyan-bar {
position: absolute;
width: 100%;
height: 90px;
background-color: #2ca1ab;
-ms-transform: rotate(-3deg);
transform: rotate(-3deg);
z-index: 1;
margin-top: -30px;
margin-left: -400px;
}
.top .purple-bar {
position: absolute;
width: 100%;
height: 50px;
background-color: #b71e4c;
-ms-transform: rotate(0.7deg);
transform: rotate(0.7deg);
margin-top: -5px;
z-index: 0;
}
<div class="top">
<div class="gray-bar"></div>
<div class="cyan-bar"></div>
<div class="purple-bar"></div>
</div>
However, when I resize my window, at some point of time, the "cyan" triangle is causing issue because of the margins and the rotation. Therefore, I added some media queries to modify the rotation angle depending on the width of the screen but I feel that it's a bit "playing around" and that there is a better solution to achieve this.
I tried using borders to make the overlapping triangles but as it cannot be expressed as percentage, I'm a bit stuck. Indeed, the goal is that the result looks about the same whatever the user's screen resolution.
Is there a better solution than mine ?
Considering that the .top element uses the full viewport width, you can use viewport percentage units for the borders. This will make the triangles relative to the viewport width.
See this example with one div :
body,html{margin:0;padding:0;}
.topBar{
position:relative;
height:35px;
border-bottom:30px solid transparent;
border-right:100vw solid #B71E4C;
}
.topBar:before, .topBar:after{
content:'';
position:absolute;
top:0; left:0;
height:15px;
}
.topBar:before{
border-bottom:50px solid transparent;
border-left:100vw solid #2CA1AB;
}
.topBar:after{
border-bottom:40px solid transparent;
border-right:100vw solid #CDCBCC;
}
<div class="topBar"></div>
Maybe this help you, but, #web-tiki its the best solution, using pseudo-selectors: :before & :after
.top {
overflow: hidden;
height: 90px;
}
.top .gray-bar {
position: relative;
width: 100%;
height: 50px;
background-color:#cdcbcc;
-ms-transform: rotate(1.3deg);
transform: rotate(1.3deg);
margin-top:-35px;
z-index: 2;
}
.top .cyan-bar {
position: relative;
width: 150%;
height: 50px;
background-color:#2ca1ab;
-ms-transform: rotate(-2deg);
transform: rotate(-2deg);
z-index:1;
top: -5px;
margin-top:-30px;
margin-left:-100px;
}
.top .purple-bar {
position: relative;
width: 100%;
height: 20px;
background-color:#b71e4c;
-ms-transform: rotate(0.7deg);
transform: rotate(0.7deg);
margin-top: -20px;
z-index:0;
}
<div class="top">
<div class="gray-bar"></div>
<div class="cyan-bar"></div>
<div class="purple-bar"></div>
</div>

How to draw a perfect hexagon with three divs?

Putting a div to the center of the viewport with position:absolute and top:50%; left:50%; transform: translate(-50%, -50%).
and using before and after elements with rotate(60deg) and rotate(-60deg).
setting the divs box-sizing: border-box; border:1px solid blue; height:40px; and 20*2*3^(1/2) seems to be 69.28xxxxxxx, so I set the width as that.
but the result seems there are some unperfect pixels at the border crossing point. I don't know how to fix it.
browser: chrome
editor:bracket
http://jsfiddle.net/gonejack/hYN67/
The borders might be distorting the shapes in your fiddle.
Check out this fiddle: http://jsfiddle.net/zqS3Q/ and replace with this code to see a solid hexagon with no borders:
#container {
position: relative;
border: 1px solid red;
margin-top: 10%;
min-height: 200px;
}
#horizontal {
position: absolute;
box-sizing: border-box;
top: 50%;
left: 50%;
height: 39px;
width: 66px;
background-color: blue;
}
#horizontal:before {
content: "";
position: absolute;
box-sizing: border-box;
height: 39px;
width: 66px;
background-color: blue;
-webkit-transform: rotate(240deg);
}
#horizontal:after {
content: "";
position: absolute;
box-sizing: border-box;
height: 39px;
width: 66px;
background-color: blue;
-webkit-transform: rotate(120deg);
}
Also, rotated boxes aren't necessarily going to be the exact specified pixel dimensions:
It seems like a chrome console bug, the console turn on then the shape would became weird, when the console high enough to give the viewport a scrollbar.
It seems to work if rather than 60deg in horizontal:after you put in -120deg. It looks like a rounding error.
http://jsfiddle.net/m3Xx8/