CSS transition - tilting test-tube containing liquid - css

I have a simple CSS3 transition that involves a test tube, containing liquid, being tilted 60 degrees to the right.
Of course, liquid always stays on the horizontal plane, and it's this effect I'm having trouble with. I do have it working in a fashion, but the liquid's transition is far from convincing.
The idea was to simply rotate the liquid element, which is a child of the tube element, by the same but opposite degree, so -60. So the net, visual effect is the liquid stays at rotation 0deg. The liquid element has adequate width to allow for this rotation without showing white space.
Code Pen: http://codepen.io/anon/pen/sIDtp (currently has only -moz prefixes, no -webkit)
HTML:
<div id='container'>
<div id='tube'><div></div></div>
<div id='tube_bottom'></div>
</div>
CSS
div, button { display: block; position: relative; }
#container {
width: 50px;
height: 150px;
top: 30px;
margin: 0 auto;
transition: -moz-transform 1s
}
#container.transition { moz-transform: rotate(60deg); }
#tube {
border: solid 6px red;
border-top: none;
border-bottom: none;
width: 100%;
height: 100%;
z-index: 1;
background: #fff;
overflow: hidden;
}
#tube_bottom {
width: 100%;
height: 30%;
border-radius: 50%;
position: absolute;
bottom: -15%;
border: solid 6px red;
background: blue;
}
#tube div {
position: absolute;
left: -175px;
width: 400px;
height: 85%;
top: 30%;
background: blue;
transition: -moz-transform 1s, top 1s;
}
#container.transition #tube div { moz-transform: rotate(-60deg); top: 70%; }
As you can see, I'm having to also modify the top property, which isn't ideal and tells me I'm probably not going about this the right way. It almost looks as if the liquid element is failing to rotate about its central point (which I believe is the default value for transform-origin.
Can anyone give me some tips as to how to make this transition look natural?

Different approach : How about skewing the water?
This tube is made with :
one div and 2 pseudo elements
transform skew and rotate
box-shadows
DEMO (no vendor prefixes)
HTML :
<div class="tube"></div>
CSS :
.tube {
border: solid 6px red;
border-top: none;
border-bottom:none;
width:50px;
height:180px;
position:relative;
margin:0 auto;
transition:transform 1s;
}
.tube:after, .tube:before {
content:'';
position:absolute;
width:100%;
background:blue;
}
.tube:after {
top:100%;
left:-6px;
width:100%;
padding-bottom:100%;
border: solid 6px red;
border-top: none;
border-bottom-left-radius: 50%;
border-bottom-right-radius: 50%;
box-shadow: 0px -30px 0px -6px blue, 0px -50px 0px -6px blue;
}
.tube:before {
bottom:0;
height: 100px;
width:50px;
z-index:-1;
transition:transform 1s;
}
.tube:hover {
transform: rotate(60deg);
}
.tube:hover:before {
transform: skewY(-60deg);
}

Since the width perspective of the tube increases as it turns, the effect speed of the tilting liquid should be inversely proportional, slower when it turns, and faster when it gets back...
I got a better looking effect by setting a different transition speed for turn, and turn back:
Updated Codepen
#tube div {
position: absolute;
left: -175px;
width: 400px;
height: 85%;
top: 30%;
background: blue;
transition: -webkit-transform 1s, top 0.5s;
}
#container.transition #tube div {
-webkit-transform: rotate(-60deg);
transition: -webkit-transform 1s, top 1.4s;
top: 70%;
}
Though it could still get some improvements... (Sorry, I changed it all to -webkit-)
But perhaps you should consider using animation and #keyframes, so you could set specific values on each percentage of the transition.

Related

CSS transition - expanding child div to its parent width and height

Here's what I got up to in terms of starting point - https://codepen.io/illianyh/pen/bGpJgma.
/*For IE CSS3 transition property works starting IE10*/
* {box-sizing: border-box;}
body {font-family: 'Playfair Display', serif; margin: 0;text-align: center}
h1 {font-weight: normal;color: #6A5953}
kbd {font-size: 0.9em;display:inline-block;line-height:1.1;}
div, h2, img {
-webkit-transition: .5s ease-in-out;
-moz-transition: .5s ease-in-out;
-o-transition: .5s ease-in-out;
transition: .5s ease-in-out;
}
h2 {
color: #E39F81;
text-shadow: 1px 1px 0 #FFE3BD;
}
h2:hover {
text-shadow: 1px 1px 0 #FFE3BD, 2px 2px 0 #FFE3BD, 3px 3px 0 #FFE3BD, 4px 4px 0 #FFE3BD, 5px 5px 0 #FFE3BD;
}
.parent {
width: 560px;
height: 386px;
margin: 0 auto;
background: black;
position: relative;
}
.box {
width: 50%;
position: absolute;
right: 0;
top: 153px;
}
.four {
width: 423px;
height: 248px;
background-color: #95A1B1;
margin: 0 auto;
}
.four:hover {
width: 500px;
height: 300px;
box-shadow: 0 15px 15px -10px rgba(0,0,0, .5);
}
<h1>CSS3 Transition examples</h1>
<div class="parent"></div>
<div class="box"><div class="four"><kbd>width, height, box-shadow</kbd></div></div>
</div>
How do I make the child to expand itself towards, inside and on top of the its parent instead of expanding itself on the outside.
Here's a diagram what I'm trying to achieve:
Initial state (the arrows represent the direction of the child expanding):
this is the final state and in the end the child div has the same width and height of the parent. The parent is now hidden behind the child:
Parent has fixed size with position relative
Child has percentage or any size type with position absoulte and top left positions related to parent fixed size (could be even percentage parent)
Transition works over known sizes
Here is an example i fixed for you: CODEPEN
.parent {
position:relative;
width: 560px;
height: 386px;
margin: 0 auto;
background: black;
position: relative;
background: red;
}
.child {
position:absolute;
background: blue;
height:70%;
width: 50%;
right: -20%;
top:15%;
box-shadow: 0 15px 15px -10px rgba(0,0,0, .5);
transition: all 0.5s ease;
}
.parent:hover .child{
top: 0%;
right: 0;
width:100%;
height:100%;
box-shadow: 0 0px 0px 0px rgba(0,0,0, .5);
}
.text{
position:absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
The solution is first to place the child inside the parent with position and size so that it is completely congruent with the parent (Let's call this the actual position of the child). Then you use the transform property with the scale and translate functions to position the child at its starting position. Finally, when the user hovers over the child, you reset the translate and scale values back to their defaults. This has the result of animating the child to the actual position.
.parent {
width: 200px;
height: 150px;
margin: 0 auto;
background: black;
position: relative;
}
.box {
transform: translate(100px, 53px) scale(0.5);
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
transition: .5s ease-in-out;
background: orange;
}
.box:hover {
transform: translate(0, 0) scale(1);
}
<h1>CSS3 Transition examples</h1>
<div class="parent">
<div class="box"></div>
</div>
This is a simplified version of the FLIP technique.

CSS transform scalex line unconsistant height

I have a hover animation on a link. A line is drawn below the text. It's 2px in height. the problem is that it starts with one height and continues with another height.
Why is it doing that? It does not need to calculate anything because 2px is a fixed number.
How can I get around it?
The animated GIF is taken in Chrome.
:root {
--cp-500: #c53e3a;
--cp-700: #8d1d2d;
--cp-800: #721228;
}
.action a {
background: linear-gradient(45deg, var(--cp-500), var(--cp-800));
color: #fff;
border-radius: 100vh;
padding: .5rem 2rem;
display: inline-block;
border: 1px solid var(--cp-700);
transition: box-shadow 150ms ease-in;
box-shadow: 0 1.25rem 1rem -1rem var(--cp-800);
z-index: 1;
text-decoration: none;
position: relative;
}
.action a:hover {
box-shadow: 0 1rem 1rem -1rem var(--cp-800);
background: var(--cp-700);
}
.action a:before {
content: '';
position: absolute;
bottom: .5rem;
left: 2rem;
width: calc(100% - 4rem);
height: 2px;
background: var(--cp-500);
transform: scaleX(0);
transform-origin: top right;
transition: transform 1000ms ease-in;
z-index: -1;
}
.action a:hover:before {
transform-origin: top left;
transform: scaleX(1);
}
<div class="action">
Test
</div>
I was also able to reproduce your issue. As AlexioVay mentioned above, you should add a scaleY also. But it's not enough, you should set the scaleY to be almost the same as scaleX. Now the line has the same height from the start till the end. See this code: https://jsfiddle.net/q236tmuk/30/
I added the following change to your css:
.action a:hover:before {
transform-origin: top left;
transform: scaleX(1) scaleY(0.99);
}
The following scenario will also work well:
.action a:hover:before {
transform-origin: top left;
transform: scaleX(1) scaleY(1.01);
}
On hover the line height is the same from the start till the end. Don't use the same value for scaleX and scaleY, because that way the height will change after the transform event. It's a browser issue. The only solution is to use a small different value for scaleY.
You mentioned that this behaviour occurs when your browser size is 125%. I could also reproduce this behaviour and tested a lot, including attributes like height and max-height which didn't affect anything.
It seems that scaleX is the main issue and because you use an increased browser size, this behaviour is only visible in this specific browser size (or a bigger browser size than 125%). So it may also behave like this at 100%, but can't be seen since 2px is too small to see it with the human eye is my guess.
Therefore I have also added scaleY(1.2) to transform: on .action a:hover:before which prevents this jittery behaviour.
:root {
--cp-500: #c53e3a;
--cp-700: #8d1d2d;
--cp-800: #721228;
}
.action a {
background: linear-gradient(45deg, var(--cp-500), var(--cp-800));
color: #fff;
border-radius: 100vh;
padding: .5rem 2rem;
display: inline-block;
border: 1px solid var(--cp-700);
transition: box-shadow 150ms ease-in;
box-shadow: 0 1.25rem 1rem -1rem var(--cp-800);
z-index: 1;
text-decoration: none;
position: relative;
}
.action a:hover {
box-shadow: 0 1rem 1rem -1rem var(--cp-800);
background: var(--cp-700);
}
.action a:before {
content: '';
position: absolute;
bottom: .5rem;
left: 2rem;
width: calc(100% - 4rem);
height: 2px;
background: var(--cp-500);
transform: scaleX(0);
transform-origin: top right;
transition: transform 1000ms ease-in;
z-index: -1;
}
.action a:hover:before {
transform-origin: top left;
transform: scaleX(1) scaleY(1.2);
}
<div class="action">
Test
</div>

Open/close loop when using transition on image

-- people suffering from epilepsy -- DON'T LAUNCH --
I prepared some kind of transition on image (translate + scale when hover). Almost everything works fine, but there is one problem. When I hover image, and drag mouse on the source place (green color), loops (open - close image starts really fast). How to avoid this behaviour?
https://codepen.io/anon/pen/KxmJdK
html, body{
height: 100%;
border: 1px solid black;
}
.container{
border: solid red 1px;
background-color: green;
}
.center{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
img{
width: 400px;
}
img:hover{
transform: scale(1.2) translate(30%, 0);
transition: all .2s ease-in-out;
box-shadow: 5px 5px 10px black;
}
<div class='center container'>
<img src='https://images.pexels.com/photos/120049/pexels-photo-120049.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940'>
</div>
You can solve this problem with just one little adjustment in css:
.container img {
display: block;
width: 400px;
}
.container:hover img {
transform: scale(1.2) translate(30%, 0);
transition: all .2s ease-in-out;
box-shadow: 5px 5px 10px black;
}
Basically u need to add the container into the equation, so it won't care if the mouse leave the image area.
codepen

Shared translucence across two elements (without overlap)?

I'm pretty sure this can't be done. But there are a lot of clever people out there, so here goes...
I'm creating an UI shape using two elements that overlap. Essentially a large square with a round protrusion.
I'd like these two elements to appear as one object (which is easy to do by giving them the same background color and overlap them) but I'd also like to have this element look like it has a single drop shadow.
The catch is that drop shadows are translucent and where the two elements overlap, you will get a darker spot due to both shadow elements combining.
Example:
http://jsbin.com/maboputexa/1/
Because these are two HTML elements, I'm pretty sure there's no way around this and this is just how it is. For now, I'm going to try not using translucent objects and go with a flat solid color for the shadow. But if anyone knows of any tricks to make this work in CSS3 with all the new options, please let me know!
(Note that I'm not referring to box-shadow properties as that wouldn't work with two objects as there always would have to be one object on top of the other).
More for the fun of it than with a real use:
2 divs, having shadows that do not overlap, and transparency that don't overlap
Notice the technique to avoid the shadows overlapping: z-index auto on the divs, and the shadow set on an pseudo element with z-index negative.
And the technique to avoid the transparency overlapping is a little disturbing, since it needs not only a mix-blend-mode, but also putting the divs behind the image ...
But, as I said, it's a funny result ...
Should work in Chrome, FF and Safari (this one untested)
body {
background-color: gray;
font-size: 30px;
}
.test1 {
width: 300px;
height: 200px;
position: absolute;
left: 150px;
top: 150px;
background-color: #555;
z-index: auto;
}
.test2 {
width: 300px;
height: 200px;
position: absolute;
left: 10px;
top: 0px;
border-radius: 50%;
background-color: #555;
z-index: auto;
-webkit-animation: move 5s infinite;
animation: move 5s infinite;
}
#-webkit-keyframes move {
0% {left: 0px; top: 0px;}
33% {left: 300px; top: 20px;}
66% {left: 300px; top: 220px;}
100% {left: 0px; top: 0px;}
}
#keyframes move {
0% {left: 0px; top: 0px;}
33% {left: 300px; top: 20px;}
66% {left: 300px; top: 220px;}
100% {left: 0px; top: 0px;}
}
.test1:after , .test2:after {
content: "";
position: absolute;
left: 0px;
toop: 0px;
width: 100%;
height: 100%;
box-shadow: 4px 4px 8px 2px black;
border-radius: inherit;
z-index: -1;
}
.overlay {
width: 600px;
height: 600px;
background-image: url(http://placekitten.com/1000/750);
background-size: cover;
position: absolute;
z-index: 4;
mix-blend-mode: overlay;
pointer-events: none;
}
<div class="test1">test1</div>
<div class="test2">test2</div>
<div class="overlay"></div>
if the goal is to draw a shape with shadow you may look at svg wich will be made for this.
CSS has limits and is not really meant for drawing:
For the CSS trick with html element, background and shadow , you can easily do the background in this case, but the shadow part will be average and a lost of precious time IMHO.
See: http://jsbin.com/paqayorewo/1/ or run snippet below.
.shape1 {
width: 200px;
height: 200px;
background: rgba(0,0,0,.5);
position: absolute;
top: 200px;
box-shadow:-3px 3px 2px 0px,
50px 50px 2px -48px,
-50px -50px 2px -48px}
.shape2 {
width: 200px;
height: 200px;
border-radius: 100px;
position: absolute;
top: 100px;
left: 100px;
overflow:hidden;
box-shadow:2px -3px 3px, -20px -20px 3px -24px, -40px -15px 2px -40px, 8px 3px 3px -3px}
.shape2:before,
.shape2:after {
content:'';
background: rgba(0,0,0,.5);
position:absolute;
}
.shape2:before {
height:50%;
width:100%;
}
.shape2:after {
width:50%;
height:50%;
top:50%;
right:0;
}
body {
position:relative;
}
<div class="shape1"></div>
<div class="shape2"></div>

Need to Fix Fuzzy pixels around CSS3 Loader

I'm making a css3 loader animation and I'm having trouble making it really crisp. Because I'm using two circles essentially, there is a slight bump in the edge because of the two overlaying circles.
Any idea on how to fix this?
http://codepen.io/anon/pen/qdylp
<div class="loader loader-2"></div>
<style type="text/css">
body {
max-width: 1000px;
margin: 100px auto 0;
padding-left: 6.25%;
}
.loader {
position: relative;
display: inline-block;
margin: 0 12.5% 100px;
width: 58px;
height: 58px;
border: 2px solid #0cf;
border-radius:50%;
box-sizing: border-box;
animation: spin 4.5s infinite linear;
}
.loader::before,
.loader::after {
left: -2px;
top: -2px;
display: none;
position: absolute;
content: '';
width: inherit;
height: inherit;
border: inherit;
border-radius: inherit;
box-sizing: border-box;
}
/*
* LOADER 2
*/
.loader-2 {
border-top-color: transparent;
background-clip: content-box;
background-clip: border-box;
}
.loader-2::after {
display: block;
left: -2px;
top: -2px;
border: inherit;
transform: rotate(300deg);
background-clip: content-box;
background-clip: border-box;
border-top: 2px solid transparent;
border-left: 2px solid transparent;
border-bottom: 2px solid transparent;
}
.stopped {
animation: spin 1004.5s infinite linear;
}
#keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
</style>
transforms will often make the appearance of an object blurry due to the way the browser manipulates the element. It doesn't look bad in Chrome, but all browsers will render it a little differently.
One way to potentially help the blurriness is to scale up, rotate, then scale back down like so:
transform: scale(4) rotate(0deg) scale(0.25);
Check out the adjusted demo to see if that's any crisper: http://codepen.io/shshaw/pen/yiHts
EDIT:
If the background color is known, then you can just have the psuedo element cover part of the circle which will render a little better: http://codepen.io/shshaw/pen/pzFtG
With an SVG, you can mask, but browser support isn't great: http://caniuse.com/#search=mask Here's a walkthrough to see if that might be what you need: http://thenittygritty.co/css-masking
Based on our conversation, the best option may be using clip on the psuedo elements with a slight rotation on one: http://codepen.io/shshaw/pen/JeBHk

Resources