I'm trying to animate between a full string of text and its abbreviation using CSS transformation transitions (demonstrated in the snippet below).
What I would ideally like to have happen is that letters that are not needed between the full and abbreviated string are scaled horizontally from 0% to 100% (or in the opposite manner), which I have functioning.
However, I would also like the non-transforming letters to compress in position as the transforming letters compress in width, and, while I can implement the former function, I cannot seem to get this one to work.
In short, the code I have written thus far successfully transforms all the letters, but leaves some letters jumping next to each other the moment the transition begins.
#bhead.smaller h1 {
position: fixed;
top: 2vh;
right: 0;
left: 0;
font-size: 3.5vh;
margin: auto;
padding: 0;
text-transform: lowercase;
transition: all 0.5s ease-out;
}
#bhead h1 div {
display: inline-block;
width: auto;
margin: 0;
padding: 0;
transition: all 5s linear;
}
#bhead h1 .del {
display: inline-block;
width: auto;
opacity: 1;
}
#bhead.smaller h1 .del {
transform: scaleX(0);
width: 0;
opacity: 0;
}
#bhead h1 .undel {
display: inline-block;
transform: scaleX(0);
width: 0;
opacity: 0;
}
#bhead.smaller h1 .undel {
transform: scaleX(1);
width: auto;
opacity: 1;
}
button {
position: fixed;
top: 15vh;
}
<body id="bhead">
<h1 id="header" class="middle unselectEase"><div>J</div><div class="del">o</div><div>r</div><div class="del">dan </div><div>Ma</div><div class="del"></div><div>nn</div><div class="undel">.com</div>
</h1>
<button onclick="document.querySelector('#bhead').className = document.querySelector('#bhead').className == 'smaller' ? '' : 'smaller'">Transform</button>
</body>
(You may need to expand the snippet in order for the spacing to work.)
Got it! After rediscovering that width must transition between two fixed values (which is also difficult with text), I was able to find this article, which described how max-width can be transitioned instead of width to avoid this altogether. The author provides a handy JSFiddle demo as well, but I've fixed the snippet below.
Given, there is a risk in setting the max-width attribute, but it's one I'm fine with taking in this specific instance.
#bhead h1 {
height: 6vh;
font-size: 6vh;
white-space: nowrap;
position: fixed;
right: 0;
left: 0;
}
#bhead.smaller h1 {
position: fixed;
top: 2vh;
right: 0;
left: 0;
font-size: 3.5vh;
margin: auto;
padding: 0;
text-transform: lowercase;
transition: all 0.5s ease-out;
}
#bhead h1 div {
display: inline-block;
margin: 0;
padding: 0;
transition: all 5s linear;
max-width: 20vw;
}
#bhead h1 .del {
display: inline-block;
opacity: 1;
}
#bhead.smaller h1 .del {
transform: scaleX(0);
max-width: 0;
opacity: 0;
}
#bhead h1 .undel {
display: inline-block;
transform: scaleX(0);
max-width: 0;
opacity: 0;
}
#bhead.smaller h1 .undel {
transform: scaleX(1);
max-width: 0;
opacity: 1;
}
button {
position: fixed;
top: 15vh;
}
<body id="bhead">
<h1 id="header" class="middle unselectEase"><div>J</div><div class="del">o</div><div>r</div><div class="del">dan </div><div>Ma</div><div class="del"></div><div>nn</div><div class="undel">.com</div>
</h1>
<button onclick="document.querySelector('#bhead').className = document.querySelector('#bhead').className == 'smaller' ? '' : 'smaller'">Transform</button>
</body>
Related
Is it possible to create an animation with CSS so that a given element (in the example, an h2 tag) when hovered moves a bit and fades out, and come back a few moments later fading in with a larger font-size.
Ideally:
This would occur on hover and the inverse when no longer hovering.
Without specifying the initial font size (in the example 2rem).
I've been trying some solutions with animations but so far nothing close to what I'm looking for.
Thanks
Edit: added short animation of what I was looking for (line is there for geometric reference of the text's position):
Edit2: the GIF if looping, but the text is supposed to remain large while the container element is hovered.
:root {
height: 100%;
background-color: lightgrey;
padding: 30px;
text-align: center;
}
h2 {
font-family: Arial;
font-size: 2rem;
}
:root:hover h2 {
font-size: 5rem;
animation: text 1s forwards ease-out;
}
#keyframes text {
0% {
transform: translateY(-30px);
opacity: 1;
}
50% {
opacity: 0;
}
100% {
}
}
<h2>TEXT</<h2>
Thank you for providing a snippet. Not sure this is what you opted for. I added a flex container to center the text, but this is optional.
:root {
height: 100%;
background-color: lightgrey;
padding: 30px;
text-align: center;
}
h2 {
font-family: Arial;
}
:root:hover h2 {
animation: text 1s forwards ease-out;
}
#keyframes text {
0% {
transform: translateY(0px);
opacity: 1;
}
25% {
transform: translateY(-30px);
opacity: 0;
font-size: 1rem;
}
50% {
opacity: 0;
}
75% {
opacity: 0;
transform: translateY(0px);
}
100% {
font-size: 5rem;
opacity: 1;
}
}
<div style="height: 150px; display:flex; align-items: center; justify-content: center;">
<h2>TEXT</h2>
</div>
UPDATE: Attempting doing the gif animation
:root {
height: 100%;
background-color: lightgrey;
padding: 30px;
text-align: center;
}
h2 {
font-family: Arial;
font-size: 2em;
margin-bottom: 0;
line-height: 1;
position: absolute;
bottom: 0;
text-align: center;
width: 100%
}
:root:hover h2 {
animation: text 1s forwards ease-out;
}
#keyframes text {
0% {
transform: translateY(0px);
opacity: 1;
}
25% {
transform: translateY(+50px);
opacity: 0;
}
50% {
opacity: 0;
font-size: 2em;
}
75% {
opacity: 0;
font-size: 5em;
transform: translateY(+50px);
}
100% {
font-size: 5rem;
transform: translateY(0px);
opacity: 1;
}
}
<div style="height: 100px; position: relative; border: 1px solid red;">
<h2>TEXT</h2>
</div>
<hr>
The root element confuses me. Nevertheless, you can add a font-size and oppacity 0 at 50 percent. The element will return to the original place afterwards. The margin-top keeps the element with the bigger font size in place. Not sure if this is the ideal solution.
Maybe just personal preference. I have changed the animation to ease-in-out, see https://www.w3schools.com/css/css3_transitions.asp
:root {
height: 100%;
background-color: lightgrey;
text-align: center;
}
h2 {
font-family: Arial;
padding: 0px;
}
:root:hover h2 {
animation: text 3s forwards ease-in-out;
}
#keyframes text {
0% {
opacity: 1;
}
50% {
opacity: 0;
font-size: 2rem;
}
100% {
opacity: 1;
margin-top: 1.5rem;
font-size: 3.5rem;
}
}
<h2>TEXT</<h2>
While building a loader icon, I noticed odd behavior in IE11 compared to Chrome, using this animation:
#keyframes loader-2 {
0% {
transform: translateX(0);
}
50% {
transform: translateX(-1.6rem);
}
100% {
transform: translateX(0);
}
}
The element correctly translates to the side at first, but then shifts super far before translating back. This only behaves this way in IE11 (works fine in Chrome/Firefox), and only on a pseudo-element (::after).
See this fiddle (or below code snippet) for an example. The top dot is a span, which works fine, the bottom dot is an ::after element, which behaves weirdly.
html {
font-size: 62.5%;
}
.splash {
align-items: center;
display: flex;
height: 100vh;
justify-content: center;
width: 100vw;
}
#keyframes loader-2 {
0% {
transform: translateX(0);
}
50% {
transform: translateX(-1.6rem);
}
100% {
transform: translateX(0);
}
}
.loader {
display: inline-block;
height: 3.2rem;
padding: 4rem 0;
position: relative;
width: 3.2rem;
border: 1px solid red;
}
.loader span {
animation: loader-2 1.5s ease infinite;
background: #024;
border-radius: 50%;
bottom: 0;
display: block;
height: 1.6rem;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 1.6rem;
}
.loader div::after {
animation: loader-2 1.5s ease infinite;
background: #024;
border-radius: 50%;
bottom: 0;
content: '';
display: block;
height: 1.6rem;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 3.2rem;
width: 1.6rem;
}
<div class="splash">
<div class="loader">
<span></span>
<div></div>
</div>
</div>
I'm able to work around this by not using pseudo-elements of course, but I would still like to know what causes this issue.
Animation and transition for pseudo-elements is not supported by IE11, check here:
https://caniuse.com/#feat=mdn-css_selectors_after_animation_and_transition_support
To work around this issue, you can try to use ID for the div and write CSS for it and avoid using pseudo.
Modified code:
html {
font-size: 62.5%;
}
.splash {
align-items: center;
display: flex;
height: 100vh;
justify-content: center;
width: 100vw;
}
#keyframes loader-2 {
0% {
transform: translateX(0);
}
50% {
transform: translateX(-1.6rem);
}
100% {
transform: translateX(0);
}
}
.loader {
display: inline-block;
height: 3.2rem;
padding: 4rem 0;
position: relative;
width: 3.2rem;
border: 1px solid red;
}
.loader span {
animation: loader-2 1.5s ease infinite;
background: #024;
border-radius: 50%;
bottom: 0;
display: block;
height: 1.6rem;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 1.6rem;
}
.loader #abc {
animation: loader-2 1.5s ease infinite;
background: #024;
border-radius: 50%;
bottom: 0;
content: '';
display: block;
height: 1.6rem;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 3.2rem;
width: 1.6rem;
}
<div class="splash">
<div class="loader">
<span></span>
<div id="abc"></div>
</div>
</div>
Output in IE 11 browser:
I am trying to add a sweep to the right animation on my image so that when you hover the image it sweeps to the right and it shows the text on hover as well. I got this to work just find with buttons but I am lost on how to go about doing this. This is what I have so far with my code:
.portfolio-box {
position: relative;
overflow: hidden;
z-index: 1;
}
.portfolio-box img {
width: 300px; /*changed this from 100% for the q*/
height:auto;
/*object-fit: contain;*/
}
.portfolio-mask {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
background: #060606;
top: 0;
left: 0;
bottom: 0;
right: 0;
height: 100%;
width: 100%;
transform: scaleX(0);
transform-origin: 0 50%;
transition: transform 0.5s ease-out;
}
.portfolio-mask:hover:after {
transform: scaleX(1);
}
.portfolio-mask:hover {
opacity: .85;
color: white;
}
<div class="portfolio-box">
<img src="https://upload.wikimedia.org/wikipedia/commons/4/45/A_small_cup_of_coffee.JPG" alt="Coffee">
<div class="portfolio-mask">
<p class="portfolio-text">Design Mock up</p>
</div>
</div>
I made some changes to your CSS to make it work smooth and without insane jumping when you hover left side of the image. Here is the CSS and below is the description what changes and why I have made.
.portfolio-box {
position: relative;
overflow: hidden;
display: inline-block;
z-index: 1;
}
.portfolio-box img {
width: 300px; /*changed this from 100% for the q*/
height:auto;
transition: all 0.5s ease-out;
display: block;
/*object-fit: contain;*/
}
.portfolio-mask {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
background: #060606;
top: 0;
left: 0;
bottom: 0;
right: 0;
height: 100%;
width: 100%;
transform: scaleX(0);
transform-origin: 0 50%;
transition: all 0.5s ease-out;
}
.portfolio-box:hover .portfolio-mask {
transform: scaleX(1);
opacity: .85;
color: white;
}
Changes I made:
Added display: inline-block; for .portfolio-box - to make it be as big as image inside.
Added display: block; for image to prevent 2-3px empty space under image when it is displayed inline (default).
Added transition: all 0.5s ease-out; for image, to prevent jumping when change position.
I changed transition from transform to all to animate not only move but opacity of mask container.
Animation are now added for hover on .portfolio-box, because it is static container, which is very important for effect you want to achieve - if you add animation on image hover then you will get infinite animation, because when you hover your mouse above image then it will slide to the right and after then it will be no longer hovered so it will go back to initial state and then it will be hovered again so it will go to the right... repeat initity ;)
I think from your description that what you are trying to do is a transform. For this, just add a translateX transform (of your desired size) to the css.
Hope this helps.
.portfolio-box {
position: relative;
overflow: hidden;
z-index: 1;
}
.portfolio-box img {
width: 300px; /*changed this from 100% for the q*/
height:auto;
/*object-fit: contain;*/
}
.portfolio-box img.animate:hover{
transform: translateX(5em);
}
.portfolio-mask {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
background: #060606;
top: 0;
left: 0;
bottom: 0;
right: 0;
height: 100%;
width: 100%;
transform: scaleX(0);
transform-origin: 0 50%;
transition: transform 0.5s ease-out;
}
.portfolio-mask:hover:after {
transform: scaleX(1);
}
.portfolio-mask:hover {
opacity: .85;
color: white;
}
<div class="portfolio-box">
<img class="animate" src="https://upload.wikimedia.org/wikipedia/commons/4/45/A_small_cup_of_coffee.JPG" alt="Coffee">
<div class="portfolio-mask">
<p class="portfolio-text">Design Mock up</p>
</div>
</div>
I am trying to do something that's fairly straightforward and I've been looking through many examples but can't seem to get this to work as I expect. What I am trying to do if have an image that on hover will scale(1.1) and then add a background-color also. As you can see I have no problem with selecting the image within the image-holder that I created and scaling this on hover but then when I try to add the overlay to this and get that to add on hover it doesn't work. I attached the code below
<div class="image-holder">
<img src="https://cdn2.artbees.net/jupiter5/orthosie/wp-content/uploads/sites/51/bfi_thumb/portfolio-feature-07-msnw0wxnyitxdmhlcfsb7elky0xl4drzq8bc37266o.jpg" width="300" height="200">
<div class="image-overlay"></div>
</div>
.image-holder {
position: relative;
max-width: 33.333%;
float: left;
overflow: hidden;
}
.image-holder img {
width: 100%;
vertical-align: top;
transition: all 0.5s;
z-index: 2;
}
.image-holder:hover img {
transform: scale(1.1);
}
.image-overlay {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0,0,0,0.9);
opacity: 0;
z-index: 5;
}
.image-overlay:hover > img {
opacity: 1;
}
Here's a simple example of what I mean.
HTML
<div class="main-container">
<div class="ht-tx1"></div>
<div class="headtest"></div>
<div class="ht-tx2"></div>
</div>
CSS
.main-container {
width: 100%;
height: 200px;
margin: 250px 0 0 0;
position: relative;
background-color: yellow;
}
.headtest {
font-family: 'quicksand', helvetica;
background-color: #a2aba2;
width: 100%;
height: 200px;
position: absolute;
top: 0;
right: 0;
}
.ht-tx1 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani1 2s forwards;
position: absolute;
top: 0;
right: 0;
}
.ht-tx2 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani2 2s forwards;
position: absolute;
bottom: 0;
right: 0;
}
#keyframes test-ani1 {
100% {
transform: translateY(-20px);
}
}
#keyframes test-ani2 {
100% {
transform: translateY(20px);
}
}
-
If you view in Chrome, both black bars slide out perfectly. The one transitioning from behind, and the one in front.
If you view it in Firefox, the bar transitioning from behind is broken. It sometimes works, but mostly it ignores the slide animation and just appears at the end of the animation duration.
I've re-created this a number of times and it seems that items that transition from behind another element are broken in firefox.
I've tried using -moz- which doesn't work. IS there anything else you can think of?
I've tried it without the absolute positioning, with z-indexs. and nothing seems to work.
EDIT ----
I appreciate work-around ideas, but I'd really like to know the route cause of this if anyone knows?
Thanks very much.
It seems Firefox is inconsistent when animate the transform property, and I can't say why (yet), most likely a bug though.
Here is 2 workarounds to achieve the same effect
.main-container {
width: 100%;
height: 200px;
margin: 50px 0 0 0;
position: relative;
background-color: yellow;
}
.headtest {
font-family: 'quicksand', helvetica;
background-color: #a2aba2;
width: 100%;
height: 200px;
position: absolute;
top: 0;
right: 0;
}
.ht-tx1 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani1 2s forwards;
position: absolute;
top: 0;
right: 0;
}
.ht-tx2 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani2 2s forwards;
position: absolute;
bottom: 0;
right: 0;
}
#keyframes test-ani1 {
0% {
transform: translateY(-1px);
}
0.1% {
transform: translateY(0px);
}
100% {
transform: translateY(-20px);
}
}
#keyframes test-ani2 {
100% {
transform: translateY(20px);
}
}
<div class="main-container">
<div class="ht-tx1"></div>
<div class="headtest"></div>
<div class="ht-tx2"></div>
</div>
.main-container {
width: 100%;
height: 200px;
margin: 50px 0 0 0;
position: relative;
background-color: yellow;
}
.headtest {
font-family: 'quicksand', helvetica;
background-color: #a2aba2;
width: 100%;
height: 200px;
position: absolute;
top: 0;
right: 0;
}
.ht-tx1 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani1 2s forwards;
position: absolute;
top: 0;
right: 0;
}
.ht-tx2 {
width: 100%;
height: 0px;
text-align: center;
background-color: #000;
animation: test-ani2 2s forwards;
position: absolute;
bottom: 0;
right: 0;
}
#keyframes test-ani1 {
100% {
top: -20px;
}
}
#keyframes test-ani2 {
100% {
height: 20px;
bottom: -20px;
}
}
<div class="main-container">
<div class="ht-tx1"></div>
<div class="headtest"></div>
<div class="ht-tx2"></div>
</div>
The solution relies on the z-index property of your elements: if you don't specify it the elements lay out one on top of the others, following the flow of the HTML document, when their "position" is set to "absolute". So "ht-txt1" is underneath "headtest" and "ht-tx2" is on top of "headtest".
To correct this "ht-tx1" and "ht-tx2" should take a "z-index" value of -1, so they are hidden underneath "headtest".
As for FF compatibility you need to prefix your "transform" effect with -moz-, check http://caniuse.com/#feat=transforms2d for more details.
Here's the CSS style code:
.main-container {
width: 100%;
height: 200px;
margin: 250px 0 0 0;
position: relative;
background-color: yellow;
}
.headtest {
font-family: 'quicksand', helvetica;
background-color: #a2aba2;
width: 100%;
height: 200px;
position: absolute;
top: 0;
right: 0;
}
.ht-tx1 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani1 2s forwards;
position: absolute;
top: 0;
right: 0;
z-index: -1;
}
.ht-tx2 {
width: 100%;
height: 20px;
text-align: center;
background-color: #000;
animation: test-ani2 2s forwards;
position: absolute;
bottom: 0;
right: 0;
z-index: -1;
}
#keyframes test-ani1 {
100% {
-ms-transform: translateY(-20px);
-webkit-transform: translateY(-20px);
-moz-transform: translateY(-20px);
transform: translateY(-20px);
}
}
#keyframes test-ani2 {
100% {
-ms-transform: translateY(20px);
-webkit-transform: translateY(20px);
-moz-transform: translateY(20px);
transform: translateY(20px);
}
}