Why does same size elements show different when zoom? - html

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>

Related

Align DIV container to bottom of page with variable height element in it

I am trying to position an element on a page so that it is always spaced away from other control elements on the page. I want this element to be positioned anywhere on the page, depending on other control elements on the page, what action the user has taken etc. These are the eight valid positions:
TOP_CENTER
TOP_LEFT
TOP_RIGHT
LEFT_CENTER
RIGHT_CENTER
BOTTOM_CENTER
BOTTOM_LEFT
BOTTOM_RIGHT
What I have so far are 3 component elements: 1) a DIV container, 2) an image which should always be at the top of the DIV container, 3) some text which should always be at the bottom of the DIV container. My CSS looks as follows:
#floatingElement {
left: 60px;
top: 11%;
width: 25%;
height: 25%;
position: absolute;
pointer-events: none;
z-index: 1;
}
#floatingElement img {
display: block;
margin: auto;
max-width: 95%;
max-height: 100%;
}
#floatingElement div {
text-align: center;
background: rgba(255,255,255,0.5);
border-radius: 5%;
box-shadow: 3px 3px 2px #888888;
font-size: 2vmax;
}
The above works perfectly whenever the element is positioned "TOP" or "CENTER". However, "BOTTOM" positioning is causing problems, I think because the container DIV is somehow not taking into account its height based on the amount of text in the 3rd (text DIV) element.
How can I make it so that the element can always align to the bottom of the page whenever a "BOTTOM" position is chosen, so that the container DIV includes the height of the text DIV (which can vary depending on the amount of text in that DIV), similar to this image:
The black border is my window, the red box is my image and the green box is the text DIV. Both the red and green boxes are inside my container DIV.
Upon being altered using bottom, the scenario you want is not working as expected because you specified the height of #floatingElement to be fixed (in your case, 25%). Having a fixed value relative to the container and not considering the height of the text div, the floating element's position will definitely seem off when altered using bottom. This is because bottom places the element based on the bottom-most pixel of your element's height, which in your case may be smaller than enough to cover your whole text div's and image's height. To see what I mean, do try removing the comment on height below and inspect the element of #floatingElement.
Here's a working example, simply click the button to adjust the div's position (try using full-page mode when running as the window is a tad small).
const button = document.querySelector('.adjustPosition')
const addText = document.querySelector('.addText')
const elem = document.querySelector('#floatingElement')
const textDiv = elem.querySelector('.textDiv')
button.addEventListener('click', e => {
if (elem.classList.contains('topLeft')) {
elem.classList.add('topCenter')
elem.classList.remove('topLeft')
} else if (elem.classList.contains('topCenter')) {
elem.classList.add('topRight')
elem.classList.remove('topCenter')
} else if (elem.classList.contains('topRight')) {
elem.classList.add('rightCenter')
elem.classList.remove('topRight')
} else if (elem.classList.contains('rightCenter')) {
elem.classList.add('bottomRight')
elem.classList.remove('rightCenter')
} else if (elem.classList.contains('bottomRight')) {
elem.classList.add('bottomCenter')
elem.classList.remove('bottomRight')
} else if (elem.classList.contains('bottomCenter')) {
elem.classList.add('bottomLeft')
elem.classList.remove('bottomCenter')
} else if (elem.classList.contains('bottomLeft')) {
elem.classList.add('leftCenter')
elem.classList.remove('bottomLeft')
} else if (elem.classList.contains('leftCenter')) {
elem.classList.add('topLeft')
elem.classList.remove('leftCenter')
}
})
addText.onclick = () => {
textDiv.innerText += "Added some more text so that the div can be larger"
}
html,
body {
height: 100%;
width: 100%;
margin: 0;
}
#floatingElement {
width: 25%;
/* height: 25%; This causes the height to be fixed */
position: absolute;
pointer-events: none;
z-index: 1;
}
#floatingElement img {
display: block;
width: 100%;
height: 100px;
margin: auto;
object-fit: cover;
}
#floatingElement .textDiv {
text-align: center;
background: rgba(255, 255, 255, 0.5);
border-radius: 5%;
box-shadow: 3px 3px 2px #888888;
}
.adjustPosition {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 25px;
height: 25px;
background: #12121299;
border-radius: 50%;
cursor: pointer;
}
.addText {
position: absolute;
top: 60%;
left: 50%;
transform: translate(-50%, -50%);
cursor: pointer;
}
.topLeft {
top: 10px;
left: 10px;
}
.topCenter {
top: 10px;
left: 50%;
transform: translateX(-50%);
}
.topRight {
top: 10px;
right: 10px;
}
.leftCenter {
top: 50%;
left: 10px;
transform: translateY(-50%);
}
.rightCenter {
top: 50%;
right: 10px;
transform: translateY(-50%);
}
.bottomLeft {
bottom: 10px;
left: 10px;
}
.bottomRight {
bottom: 10px;
right: 10px;
}
.bottomCenter {
bottom: 10px;
left: 50%;
transform: translateX(-50%);
}
<div id="floatingElement" class="topLeft">
<img src="https://homepages.cae.wisc.edu/~ece533/images/airplane.png">
<div class="textDiv">Variable height here because it has a long text</div>
</div>
<div class="adjustPosition"></div>
<div class="addText">Add Text</div>

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

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>

How to give a matte-finish (non-glassy) look to an image with CSS?

I would like to show the image with a non glassy display. Similar to the following one,
I am using the image as it is. I would like to show that with matte finish.
normal image:
Matte finish:
I am not able find it online. May be I am not using the right search keywords. Could anyone help me with this?
Inside a container I did put an image with reduced contrast / brightness / saturation plus a little bit of blur (all these four effects made by CSS filter). The image could've be placed as the container background but I wanted to apply these filters so it went separated.
After it, there's a colored layer with transparency covering the whole area. The letter represents the page's content that can be anything.
UPDATE: multiple filters must be all in a row, like it is on this latest update:
body {
width: 100%;
height: 100vh;
margin: 0px;
font-family: Georgia, serif;
}
#container {
width: 100%;
height: 100%;
position: relative;
background-color: navy;
overflow: hidden;
}
#thepic {
width: 100vw;
height: 100vh;
object-fit: cover;
-webkit-filter: brightness(90%) contrast(90%) blur(2px) grayscale(10%);
filter: brightness(90%) contrast(90%) blur(2px) grayscale(10%);
}
#color_layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: navy;
opacity: 0.3;
}
#content {
position: absolute;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
left: 0;
right: 0;
margin: auto;
text-align: center;
}
h1 {
display: inline-block;
color: white;
text-shadow: 1px 2px 2px #000;
font-size: 4em;
font-weight: 100;
letter-spacing: 2px;
text-align: center;
vertical-align: middle;
}
#letter {
vertical-align: middle;
}
<div id=container>
<img id=thepic src="http://i.imgur.com/s9J4MnI.jpg">
<div id=color_layer></div>
<span id=content><img id=letter src="http://i.imgur.com/CB1vUqy.png" alt=img><h1> 書面</h1></span>
</div>
#freestock.tk - That's the idea I had in mind also.
Here's another way to do it with less markup:
img {
max-width: 100%;
height: auto;
}
.container {
position: relative;
z-index: -1;
}
.container:before {
content: "";
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0.5);
}
<div>
<h1>Original Image</h1>
<img src="http://i.imgur.com/WjbwTUH.jpg">
</div>
<div class="container" id="content">
<h1> With Transparent Overlay </h1>
<img src="http://i.imgur.com/WjbwTUH.jpg">
</div>
In this example, I put the image inside a container that is relatively positioned. The z-index is -1 so it will be behind the next layer.
Then I used a pseudo element that is absolutely positioned so it will stretch across the whole width of the container and cover the image. The positive z-index sets it on top of the first layer. Rather than setting an opacity, I used an rgba value for the background color. The first three numbers or the red, green, and blue values as usual, but the last number is a decimal between 0 and 1 that sets the opacity level. I made it a little darker than you probably want just so you can see the difference. You may also choose a different color to fit your image.
For reference: http://nicolasgallagher.com/css-background-image-hacks/

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/