CSS bad rendering in translateZ( ) vs scale( ) - css

I noticed that there is a big quality difference when transforming text in this 2 ways:
.text1 {
width: 200px;
height: 22px;
position: absolute;
top: 40%;
left: 0;
transform-origin: 50% 50%;
transform: scale(2); /* here */
color: red;
text-align: center;
font-size: 22px;
}
.text2 {
width: 200px;
height: 22px;
position: absolute;
top: 60%;
left: 0;
transform-origin: 50% 50%;
transform: translateZ(400px); /* here */
text-align: center;
font-size: 22px;
}
.perspective {
width: 200px;
height: 200px;
perspective: 800px;
transform-style: preserve-3d;
}
<div class="perspective">
<div class="text1">Text</div>
<div class="text2">Text</div>
</div>
Is there a way to force a better rendering when displacing text on the Z axis?

the reason the text blurs when you're transforming with translateZ(400px) is that this is a 3D transformation ; the browser treats the element as textures instead of vectors in order to provide hardware 3d acceleration.
So basically the resolution will be lower when increasing size.
On the other hand transforming with scale is a 2D transformation,
the browser treats the element as vector and blurring doesn't occur.
take a look at what happens to scale as soon as we kick in with 3d, without actually setting any translateZ value:
.text1 {
width: 200px;
height: 22px;
position: absolute;
top: 40%;
left: 0;
transform-origin: 50% 50%;
transform: scale(2);
/* here */
color: red;
text-align: center;
font-size: 22px;
}
.text1a {
width: 200px;
height: 22px;
position: absolute;
top: 40%;
left: 50%;
transform-origin: 50% 50%;
transform: translateZ(0) scale(2);
/* here */
color: blue;
text-align: center;
font-size: 22px;
}
.text2 {
width: 200px;
height: 22px;
position: absolute;
top: 60%;
left: 0;
transform-origin: 50% 50%;
transform: translateZ(400px);
/* here */
text-align: center;
font-size: 22px;
}
.perspective {
width: 200px;
height: 200px;
perspective: 800px;
transform-style: preserve-3d;
}
<div class="perspective">
<div class="text1">Text</div>
<div class="text1a">Text</div>
<div class="text2">Text</div>
</div>
the only workaround I can think of at the moment is checking the stylesheet through JS and overriding translateZ with transform: scale
var styles = document.styleSheets;
//patterns
var perspPat = /perspective\s*?:\s*?(\d+)/;
var transZPat = /translateZ\(\s*?(\d+)/;
var perspective;
var translateZ = [];
[].slice.call(styles).forEach(function (x) {
[].slice.call(x.rules).forEach(function (rule) {
if (perspPat.test(rule.cssText)) {
perspective = perspPat.exec(rule.cssText)[1]
};
if (transZPat.test(rule.cssText)) {
translateZ.push([
rule.selectorText,
transZPat.exec(rule.cssText)[1]]);
}
});
})
translateZ.forEach(function (x) {
document.querySelector(x[0]).style.transform = 'scale(' + perspective / x[1] + ')';
})
fiddle
As you can see, even if it does work, a lot of optimization is needed..
(I wouldn't consider it production ready in it's current state ).

You can add font-smooth (for firefox), and antialiasing for webkit
.text2 {
-webkit-font-smoothing: antialiased;
font-smooth: always;
}
https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth
http://davidwalsh.name/font-smoothing

Related

CSS TranslateX doesn't move to the right of div

I'm trying to get the toggle to move it 100% to the right. As I'm trying to make it responsive, I can't set it to move an xx amount of pixels.
Can you please help?
input:checked + .slider:before {
-webkit-transform: translateX(100%);
-ms-transform: translateX(100%);
transform: translateX(100%);
}
https://jsfiddle.net/Lc1tdhgb/1/
Thanks
setTimeout(function() {
document.getElementById('togBtn').checked = true;
}, 1000)
#toggle {
width: 100%;
height: 100%;
position: relative;
}
.switch {
position: absolute;
display: inline-block;
width: 100%;
/*min-height: 32px;*/
height: auto;
top: 0;
}
.switch input {
display: none;
}
.slider {
cursor: pointer;
background-color: #ca2222;
-webkit-transition: .5s;
transition: .5s;
border-radius: 32px;
padding: 12px 0;
}
.slider:before {
position: absolute;
content: "";
height: 1.1em;
width: 1.1em;
left: 3px;
bottom: 3px;
background-color: white;
-webkit-transition: .5s;
transition: .5s;
border-radius: 50%;
}
input:checked+.slider {
background-color: #3eab37;
}
input:focus+.slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked+.slider:before {
left: calc(100% - 20px);
/*-webkit-transform: translateX(100%);
-ms-transform: translateX(100%);
transform: translateX(100%);*/
}
/*------ ADDED CSS ---------*/
.slider:after {
content: 'OFF';
color: white;
display: block;
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
font-size: 0.7em;
font-family: Roboto, sans-serif;
}
input:checked+.slider:after {
content: 'ON';
}
/*--------- END --------*/
<div id="toggle">
<label class="switch"><input type="checkbox" id="togBtn"><div class="slider round"></div></label>
</div>
Well, just make sure that the container of the elements follow a position: relative;, so the wrapper have the restrains for the absolute elements inside of it. Then, right is actually how far from right you want the element to be, in this case, you could've used either right: 0%; or left: 100%; although you've encountered the error in the fact that you'd be ignoring margins from the parent's style. That's why I added left: calc(100% - 20px); (20px was on trial and error, until I got it aligned with the outter border of the switch!), then now it works as wanted. Glad to help :)

Why translateZ working not working on hover?

When I hover over the image, the transition works fine except for the fact that the front image (that of a rotating lock) only translates 20px in Z direction when the mouse is removed from that image. I want the rotating lock image to be 20px in front always.
Also, why does the rotating lock image becomes slightly smaller just after I hover the image?
body {
margin:0;
width: 100%;
height: 100%;
}
.maincircle {
width: 200px;
height: 200px;
position: relative;
margin-left: 200px;
margin-top: 10px;
border-radius: 50%;
border: 1px solid black;
perspective: 600px;
transform-style: preserve-3d;
}
.door {
background-color: gray;
border-radius: 100%;
height: 200px;
margin: 0;
position: relative;
width: 200px;
transition: .5s linear;
transform-style: preserve-3d;
transform-origin: 0 50%;
transition: transform 2s 0.5s;
}
.door:before {
background-color: gray;
background-image: linear-gradient(hsla(0,0%,100%,.25), hsla(0,0%,0%,.25));
border-radius: 100%;
content: '';
height: 200px;
left: 0;
position: absolute;
top: 0;
width: 200px;
transform: translateZ(-5px);
}
.door:after {
background-color: gray;
background-image: linear-gradient(hsla(0,0%,100%,.25), hsla(0,0%,0%,.25));
bottom: 0;
content: '';
left: 100px;
position: absolute;
top: 0;
width: 5px;
z-index: -10;
transform: rotateY(-90deg);
transform-origin: 100% 50%;
}
.maincircle:hover .door {
transform: rotateY(-110deg);
}
.maincircle:hover .locker {
transform: rotate(90deg);
}
.locker {
background-image: url("https://irp-cdn.multiscreensite.com/806e9122/dms3rep/multi/tablet/CombinationLock-1000x1000.png");
position: absolute;
top: 25px;
left: 25px;
background-size: 100% 100%;
border-radius: 100%;
width: 150px;
height: 150px;
transform: translateZ(20px);
transition: transform 0.5s;
}
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="maincircle">
<div class="door">
<div class="locker"></div>
</div>
</div>
</body>
</html>
Question 1: (I want the rotating lock image to be 20px in front always)
It is because transform settings are not additive in nature. When you specify the transform during the :hover as give below,
.maincircle:hover .locker {
transform: rotate(90deg);
}
it overwrites the transform: translateZ(20px) that is specified within the default state (which is the setting under .locker selector) and so the translation in Z-axis is lost whenever the element is being hovered. It gets applied back only when the :hover is off (that is, the element returns to default state as specified in .locker selector).
In order to always have the translation in Z-axis, translateZ(20px) should be added to the transform stack within :hover selector also like below:
.maincircle:hover .locker {
transform: rotate(90deg) translateZ(20px);
}
body {
margin:0;
width: 100%;
height: 100%;
}
.maincircle {
width: 200px;
height: 200px;
position: relative;
margin-left: 200px;
margin-top: 10px;
border-radius: 50%;
border: 1px solid black;
perspective: 600px;
transform-style: preserve-3d;
}
.door {
background-color: gray;
border-radius: 100%;
height: 200px;
margin: 0;
position: relative;
width: 200px;
transition: .5s linear;
transform-style: preserve-3d;
transform-origin: 0 50%;
transition: transform 2s 0.5s;
}
.door:before {
background-color: gray;
background-image: linear-gradient(hsla(0,0%,100%,.25), hsla(0,0%,0%,.25));
border-radius: 100%;
content: '';
height: 200px;
left: 0;
position: absolute;
top: 0;
width: 200px;
transform: translateZ(-5px);
}
.door:after {
background-color: gray;
background-image: linear-gradient(hsla(0,0%,100%,.25), hsla(0,0%,0%,.25));
bottom: 0;
content: '';
left: 100px;
position: absolute;
top: 0;
width: 5px;
z-index: -10;
transform: rotateY(-90deg);
transform-origin: 100% 50%;
}
.maincircle:hover .door {
transform: rotateY(-110deg);
}
.maincircle:hover .locker {
transform: rotate(90deg) translateZ(20px);
}
.locker {
background-image: url("https://irp-cdn.multiscreensite.com/806e9122/dms3rep/multi/tablet/CombinationLock-1000x1000.png");
position: absolute;
top: 25px;
left: 25px;
background-size: 100% 100%;
border-radius: 100%;
width: 150px;
height: 150px;
transform: translateZ(20px);
transition: transform 0.5s;
}
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="maincircle">
<div class="door">
<div class="locker"></div>
</div>
</div>
</body>
</html>
Question 2: (Why does the rotating lock image becomes slightly smaller just after I hover the image?)
I am putting this at the last (even below the code) because I know by now you'd have guessed why it became smaller. It becomes smaller because the element is losing the translateZ(20px) and so it is going farther away from your eye. Any object that goes farther away from the eye will look smaller.

CSS3: Transforming ONLY during Transition

I know we can transform shape (e.g. circle to square) from one state (e.g. top: 0) to another state (e.g. top: 20px). But I'm not sure how we can keep the shape at both states intact (i.e. keeps it circled # top: 0 and top: 20px), but ONLY during transition I want to transform its shape. An example of what I want to achieve is somewhat like this:
Here's a pure css version of what you want. It transforms only during the transition. Not hard at all. Just use keyframes to specify what properties you want changed and when.
The HTML
<div class="childAnimated"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
And the CSS
.child {
border: .5em solid white;
width: 3em;
height: 3em;
border-radius: 5em;
margin-bottom: 1em;
}
.childAnimated {
position: fixed;
top: 1em;
left: 1em;
z-index: 999;
background-color: white;
width: 3em;
height: 3em;
border-radius: 5em;
-webkit-animation: gooAnim 4s infinite;
}
#-webkit-keyframes gooAnim {
0% { top: 1em; }
25% { top: 3.8em; left: 1.5em; width: 2em; height: 2em; }
50% { top: 6em; width: 3em; height: 3em; left: 1em;}
75% { top: 8.8em; left: 1.5em; width: 2em; height: 2em; }
100% { top: 11em; }
}
If you want to see it in action, here's the codepen. Run it in Chrome if you can. http://codepen.io/shuffguy/pen/JdLXeM
This was a quick example, but if you play around with the keyframe resizing properties you can definitely emulate that example exactly with keyframes.
U can use the #keyframe animation in css for this, just take a look: https://css-tricks.com/snippets/css/keyframe-animation-syntax/
And here is a exemple what i made with keyframes and jquery animate:
Css
#box{
display: block;
background: red;
width: 300px;
height: 300px;
border-radius: 100%;
position: relative;
}
#keyframes change_form {
0% {
width: 300px;
}
50% {
border-radius: 0%;
width: 50px;
height: 100px;
}
100% {
width: 300px;
height: 300px;
}
}
Jquery
$(document).ready(function(){
window.setTimeout(function(){
$( "#box" ).animate({
"top":"+=134px"
,
},{
step: function(now) {
if (now >= 11) {
$("#box").css({'transition':'all linear 1s', 'animation':'change_form ease 2s '});
}
} }
);
}, 2000);
});
In a simple Div
<div id="box"></div>
Just a example what i make to show u how to make this effect, u can make this only with css, just putting the 'animation' in your div

Recreate this radial image using css

I would like to know if it's possible to recreate the following image using css.
I am currently using it but in svg format.
Imagine this:
jsfiddle link
#circle {
background: #ccc;
border-radius: 50%;
/* Change these two equally to change circle size. Can be pixels, too. */
width: 25%;
padding-top: 25%;
height: 0;
position: relative;
}
.hand {
background: black;
width: 1px;
height: 100%;
position: absolute;
left: 50%;
top: 0;
}
.hand:nth-child(2) {
transform: rotate(90deg);
}
.hand:nth-child(3) {
transform: rotate(45deg);
}
.hand:nth-child(4) {
transform: rotate(135deg);
}
#circle:after {
content: '';
display: block;
width: 80%;
height: 80%;
border-radius: 50%;
background: white;
position: absolute;
top: 10%;
left: 10%;
}
<div id="circle">
<div class="hand"></div>
<div class="hand"></div>
<div class="hand"></div>
<div class="hand"></div>
</div>
Or if you need the middle to be transparent (this is a little hacky, and you may have to modify it to fit your exact needs): https://jsfiddle.net/wdoe8r3m/1/

How to make a unicode triangle wider

I'm using a pseudo-element of content to make a triangle that I want floating outside the upper
Setup of problem: Get the blue triangle on this fiddle to be wider (but keep its height)
.bluebox { margin-top: 50px; background: blue; min-width: 300px; min-height: 200px; position: relative;}
.bluebox:after { content: "\25B2"; color: blue; position: absolute; font-size: 2em; top: -0.8em; left: 5%;}
What attribute to I need to tweak in order to do that?
If supporting IE8 and below is not a concern, you could apply scaleX() transform function with to the pseudo-element.
For instance (Vendor prefixes omitted due to brevity):
.bluebox:after {
/* other declarations... */
content: "\25B2";
transform: scaleX(1.5);
}
Online Example:
.bluebox {
margin-top: 50px;
background: blue;
min-width: 300px;
min-height: 200px;
position: relative;
}
.bluebox:after {
content: "\25B2";
color: blue;
position: absolute;
font-size: 2em;
top: -0.8em; left: 5%;
-webkit-transform: scaleX(1.5);
-moz-transform: scaleX(1.5);
-ms-transform: scaleX(1.5);
-o-transform: scaleX(1.5);
transform: scaleX(1.5);
}
<div class="bluebox"></div>

Resources