Smooth CSS Transform Scale on rectangle, keeping an even border - css

I have an absolutely positioned div that I want to have slowly increase in size (5s transition) on hover, to become a "border" for a relative-positioned div on top of it:
<div class="rectangle">
<div class="background"></div>
<div class="content">blah</div>
</div>
Styles (vendor prefixes removed for readability):
.rectangle {
position: relative;
}
.background {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.content {
height: 800px;
width: 200px;
}
Transitioning the overall .background size results in choppy animation but an even border:
.rectangle:hover .background {
width: calc(100% + 40px);
height: calc(100% + 40px);
top: -20px;
left: -20px;
right: -20px;
bottom: -20px;
transition: 5s linear all;
}
Transitioning a border is choppy animation, but (obviously) an even border
.rectangle:hover .content {
border: 20px solid red;
transition: 5s linear all;
}
Transitioning a transform-scale is smooth, but results in a larger top and bottom "border" because it is a rectangle:
.rectangle:hover .background {
transition: 5s transform;
transform: scale(1.1);
}
Any way to either get transform-scale to keep even dimensions, or any other way to create this effect?

You can try using box shadow as a border to achieve smooth transitions.
.rectangle {
position: relative;
width: 300px;
height: 300px;
top: 100px;
left: 30%;
}
.background {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.background::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0 0 0 0px #000;
transition: 5s linear box-shadow;
}
.content {
height: 300px;
width: 200px;
}
.rectangle:hover .background::before {
box-shadow: 0 0 0 20px #000;
transition: 5s linear box-shadow;
}
<div class="rectangle">
<div class="background"></div>
<div class="content">blah</div>
</div>

Related

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.

CSS transitions in different directions

I am trying to fill a wrapper (600x600px) when hovering over smaller boxes inside it. For a box in the top left corner, it is easily done using regular transition-timing-function, but when trying to enlarge in other directions, I have gotten stuck.
So I have the following:
#allbox {
background: #bbb;
width: 600px;
height: 600px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0
}
with boxes:
div.box1 {
position: absolute;
top: 0%;
left: 0%;
}
div.box2 {
position: absolute;
top: 0%;
left: 37.5%;
}
For transition I use:
#div1 {-webkit-transition-timing-function: linear;}
#div1 {transition-timing-function: linear;}
div.box1:hover {
width: 600px;
height: 600px;
}
But I am unable to figure a good way to do it for the following box.
Here is a sample using z-index keeping the hovered on top.
#allbox {
background: #bbb;
width: 600px;
height: 300px;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0
}
#allbox div {
position: absolute;
z-index: 1;
top: 0%;
width: 33.33%;
height: 50%;
transition: left 0.5s linear, width 0.5s linear, height 0.5s linear, z-index 1s linear;
}
div.box1 {
left: 0;
background: blue;
}
div.box2 {
left: 33.33%;
background: red;
}
div.box3 {
left: 66.66%;
background: green;
}
#allbox div:hover {
z-index: 2;
left: 0;
width: 100%;
height: 100%;
transition: left 0.5s linear, width 0.5s linear, height 0.5s linear, z-index 0s linear;
}
<div id="allbox">
<div class="box1">
</div>
<div class="box2">
</div>
<div class="box3">
</div>
</div>
I think we just add "left: 0;" to the hover state.
div.box2:hover {
left: 0;
width: 600px;
height: 600px;
}
Hope this help you.

"position: fixed" not woking when parent has the "transform" CSS property

In my project I have screen which should ease-in from right side of the screen so for that thing I have used transform: translateX(100%) and then changing that to transform: translateX(0%). it works fine I able to achieve the ease-in effect but in that screen I have action button which has css property of Position: Fixed;Bottom: 0px; but this is not working I mean its not sticking in the bottom of the screen.
Here is my JSfiddle : https://jsfiddle.net/sureshpattu/a1seze4x/
Html:
<header>
Heading
</header>
<div class="page__popup page__popup--ease-in-right page__action-btn--visible" style="height: 382px;">
<div class="container">
</div>
<button class="js-action-btn">
SELECT ROOMS
</button>
</div>
Css:
header {
background: #fff;
height: 60px;
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
z-index: 10;
box-shadow: 2px 2px 10px #000;
}
.container {
height: 382px;
}
.page__popup {
position: absolute;
top: 100vh;
z-index: 8;
display: block;
overflow-y: scroll;
max-height: 100vh;
width: 100%;
height: 0;
background: #ffffff;
.js-action-btn {
position: relative;
bottom: -50px;
transition: all 0.25s ease-in-out;
}
//Themes
&--ease-in-bottom {
&.visible {
transition: height 0.25s ease-in-out;
top: 54px;
right: 0;
bottom: 0;
left: 0;
}
}
&--ease-in-right {
transform: translateX(100%);
height: 100vh;
top: 60px;
&.visible {
transition: transform 0.25s ease-in-out;
transform: translateX(0);
}
}
}
.page__action-btn--visible {
.js-action-btn {
background: red;
width: 100%;
height: 30px;
position: fixed;
bottom: 0;
z-index: 10;
box-shadow: 0 7px 4px 10px rgba(0, 0, 0, .12);
}
}
This is not a bug.
Take a look at the spec: The Transform Rendering Model
Specifying a value other than ‘none’ for the ‘transform’ property
establishes a new local coordinate system at the element that it is
applied to.
So according to the spec: the element with fixed positioning will become relative to the element with the transform - not the viewport
As a workaround you could:
1) Use transitions (eg. on the left property) instead of transform (translateX)
2) Remove the position:fixed button from the container which uses transforms

Animate growing div then animate child element

I'm currently trying to animate a growing <div> but I don't want the content to look like it is growing along with it. The content should remain invisible while the <div> is animating and once it's fully grown I'd like for the content to become visible (by changing the opacity of the <a> in that <div>).
This is the code for the <div> animation:
#keyframes menu {
0% {
background-color: white;
right: -25px;
top: -25px;
border-radius: 100px;
width: 0px;
height: 0px;
}
25%{
right: -50px;
top: -50px;
border-radius: 100px;
width: 60px;
height: 60px;
}
50% {
right: -50px;
top: -50px;
width: 80px;
height: 80px;
border-radius: 100px;
}
75%{
right:-50px;
top:-50px;
width: 150px;
height: 150px;
border-radius: 100px;
}
80%{
right:-50px;
top:-50px;
width: 300px;
height: 300px;
border-radius: 300px;
}
100%{
right:-150px;
top:-150px;
width: 450px;
height: 450px;
border-radius: 600px;
}
}
It's basically a menu that starts in the corner and grows until the full screen is covered (mobile). I've tried adding a{ opacity: 1 }; but I guess it doesn't work like that.
If you want the anchor text (within the div) to be visible only after the animation on the parent div is fully complete then add another animation to the a, animate the opacity from 0 to 1 after a delay which is equal to the animation-duration of the parent.
div {
background-color: black;
line-height: 450px;
text-align: center;
animation: menu 4s linear forwards;
}
a {
color: white;
text-decoration: none;
animation: display 1s linear 4s backwards;
}
#keyframes menu {
0% {
background-color: white;
right: -25px;
top: -25px;
border-radius: 100px;
width: 0px;
height: 0px;
}
25% {
right: -50px;
top: -50px;
border-radius: 100px;
width: 60px;
height: 60px;
}
50% {
right: -50px;
top: -50px;
width: 80px;
height: 80px;
border-radius: 100px;
}
75% {
right: -50px;
top: -50px;
width: 150px;
height: 150px;
border-radius: 100px;
}
80% {
right: -50px;
top: -50px;
width: 300px;
height: 300px;
border-radius: 300px;
}
100% {
right: -150px;
top: -150px;
width: 450px;
height: 450px;
border-radius: 600px;
}
}
#keyframes display {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
<div>
<a href='#'>Some Menu Link</a>
</div>
I would use a little jQuery to do that. Using a callback you can call opacity 1 on a after the div is complete grown.
$( ".yourdiv" ).animate({
width: "450"
height: "450"
}, 5000, function() {
//callback will cause the a to change its opacity only when the above function is complete
$('.yourdiv a').css('opacity') = '1';
});

Center a absolute positioned div vertical?

I have this:
.ce_text.forward {
position: relative;
overflow: hidden;
padding: 20px;
background-color: #F8F8F8;
color: #2d353c;
}
.ce_text.forward p {
position: relative;
}
.ce_text.forward .fill_bottom {
width: 500px;
height: 500px;
bottom: 0;
left: -865px;
position: absolute;
margin: auto;
background-color: #ecedee;
top: 0px;
right: 0;
transition: left 0.3s linear 0s;
transform: rotate(45deg);
}
.ce_text.forward:hover .fill_bottom {
left: 0;
}
<div class="ce_text forward block"><div class="fill_bottom"></div>
<p><strong>Headline</strong>Test Test test test<span>Lesen Sie mehr</span></p>
</div>
It works in chrome but not in firefox, can some one help me with the css?
Fiddle
The problem in Firefox seems to be caused by the usage of margin: auto. I have completely re-built your example to eliminate this.
New and Improved
No fixed height. Height is controlled by a percentage (which can be modified) and a min-height.
No extra markup. The triangle is created with a pseudo element and rotated. The text is centered with its <a> wrapper.
Centered triangle. The triangle is centered at any height with bottom: 50% and a negative bottom margin of half its height.
No gaps - The triangle is large enough to eliminate any spacing in the corners. If you need it to be even larger, it can be as large as required; just keep the height to width ratio 1:1 and increase the size of the negative bottom margin.
* {
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
h1 {
background: #333;
height: 40%;
min-height: 140px;
position: relative;
overflow: hidden;
z-index: 0;
}
h1 a {
display: block;
height: 100%;
position: absolute;
top: 50%;
margin-top: -0.56em;
left: 100px;
}
h1:before {
content:'';
display: block;
position: absolute;
bottom: 50%;
margin-bottom: -1000px;
left: -2000px;
height: 2000px;
width: 2000px;
background: #F00;
transform: rotate(45deg);
transition: left 0.3s;
z-index: -1;
}
h1:hover:before {
left: 0;
}
<h1><a>Text</a></h1>
Old Solution
Archived - fixed height option (no transform, should work back to IE8)
I have approached this differently:
The right triangle and the bar are made with pseudo elements and are positioned with percentages
z-index: -1 keeps the pseudo elements behind the text.
overflow: hidden prevents the scroll bar when the triangle is pushed outside.
* {
margin: 0;
padding: 0;
}
.headline {
height: 100px;
background: #333;
color: #FFF;
position: relative;
z-index: 2;
display: inline-block;
width: 100%;
height: 0;
padding: 30px 0 70px 50px;
overflow: hidden;
}
.headline:before {
width: 30%;
content:'';
display: block;
height: 100px;
background: #F00;
position: absolute;
top:0;
left: 0;
transition: all 0.3s linear 0s;
z-index: -1;
}
.headline:after {
content: '';
display: block;
border-bottom: solid 50px transparent;
border-top: solid 50px transparent;
border-left: solid 50px #F00;
height: 0;
width: 0;
left: 30%;
position: absolute;
top:0;
transition: all 0.3s linear 0s;
z-index: -1;
}
.headline:hover:before {
width: 100%;
}
.headline:hover:after {
left: 100%;
}
<h1 class="headline">Text</h1>

Resources