This question already has answers here:
Dashed border animation in css3 animation
(7 answers)
Closed 7 months ago.
I'm trying to animate a border of a logo that's just two letters. I can't figure out how to animate the border of my logo so I resorted to creating 4 divs with different borders (top, down, left, right) and animate them one by one. However, the animation isn't seamless as it keeps snapping back to its original location, and the div wrapper I created can't contain the animation overflowing outside.
I'm new to css animations so I'm wondering if there is a way to make an animated moving dashed border for a logo.
Here's my jsfiddle (first time using jsfiddle so let me know if the link doesnt work)
/* div border for top */
.logo-border-up {
background-color: transparent;
border-top: 10px dashed #252422;
width: 5rem;
height: 10px;
position: absolute;
animation: animate-up 1s linear infinite;
}
#keyframes animate-up {
0% {
transform: translatex(0%);
}
100% {
transform: translatex(100%);
}
Edit: I managed to solve it. Thanks to this stackoverflow Dashed border animation in css3 animation
To eliminate the animation snapping back to the beginning when it reaches the end, a minor modification can be applied to your existing code:
position: relative
Your animation will now be contained within <div class="logo-wrapper">.
As the moving border is just a visual clue rather than part of the content here is a snippet which draws and animates it using pseudo elements rather than putting extra elements into the DOM.
linear-gradients are used to draw background images of dashes which are repeated in the horizontal or vertical direction as appropriate.
The background positions are then animated using CSS keyframes.
The after and before pseudo elements are made slightly bigger than the wrapper and positioned so the borders are slightly outside.
The logo characters are centered within the wrapper using flex.
Sizing of the dashes is done relative to the size of the wrapper rather than mixing px and rem values which can make things difficult to adjust relatively (rem can be changed for example).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght#400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<title>Logo</title>
<style>
body {
background-color: #FFFCF2;
}
.logo-wrapper {
width: 5rem;
aspect-ratio: 1 / 1;
roverflow: hidden;
position: relative;
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
}
.logo {
font-family: 'Poppins', sans-serif;
font-size: 3rem;
text-decoration: none;
font-weight: 700;
color: #252422;
/* border: 0.5rem dashed #252422; */
}
.logo-wrapper::before,
.logo-wrapper::after {
content: '';
position: absolute;
top: -5%;
left: -5%;
width: 110%;
aspect-ratio: 1 / 1;
overflow: hidden;
animation: var(--name) 2s linear infinite;
}
.logo-wrapper::before {
background-image: linear-gradient(to right, #252422 0 50%, transparent 50% 100%), linear-gradient(to right, transparent 0 50%, #252422 50% 100%);
background-size: 25% 6.25%;
background-repeat: repeat no-repeat;
background-position: 0 0, 100% 100%;
--name: horizMove;
}
.logo-wrapper::after {
background-image: linear-gradient(#252422 0 50%, transparent 50% 100%), linear-gradient(transparent 0 50%, #252422 50% 100%);
background-size: 6.25% 25%;
background-repeat: no-repeat repeat;
background-position: 100% 0, 0 100%;
--name: vertMove;
}
#keyframes horizMove {
0% {
background-position: 0 0, 100% 100%;
}
100% {
background-position: 100% 0, 0 100%;
}
}
#keyframes vertMove {
0% {
background-position: 100% 0, 0 100%;
}
100% {
background-position: 100% 100%, 0 0;
}
}
/*
.logo-border-up {
background-color: transparent;
border-top: 10px dashed #252422;
width: 5rem;
height: 10px;
position: absolute;
animation: animate-up 1s linear infinite;
}
*/
#keyframes animate-up {
0% {
transform: translatex(0%);
}
100% {
transform: translatex(100%);
}
}
#keyframes animate-down {
0% {
transform: translatex(0%);
}
100% {
transform: translatex(-100%);
}
}
</style>
</head>
<body>
<nav>
<div class="logo-wrapper">
<div class="logo-border-up"></div>
bt
</div>
</nav>
</body>
</html>
Note: setting all background colors as is done in the code given in the question can lead to unexpected results. This snippet has removed that and put the background color on the body.
Related
I am trying to make my scrollbar change color,gradient like, when scrolling. Now it is fixed to a gradient color no matter if it is on top or bottom of the page.
Can this happen? Chnge color on scroll?
EDIT:
/* width */
::-webkit-scrollbar {
width: 19px;
}
/* Track */
::-webkit-scrollbar-track {
background: rgba(0,0,0,1);
border-color:black;
border-radius:20px;
}
/* Handle */
::-webkit-scrollbar-thumb {
background-image: linear-gradient(to bottom, #ee7752, #e73c7e, #23a6d5, #23d5ab);
animation: scroll-gradient 5s ease infinite;
background-size: 100% 100%;
border-radius:20px;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #7333B1;
}
body {
height:100vw;
}
<body>
<h1 style="height:200px">hello</h1>
</body>
As you can see the bar is static gradient. Is there any way to make the scrolbarr gradient change when scrolling?
I've edited your code a bit, I hope it's what you were looking for.
/* width */
body::-webkit-scrollbar {
width: 19px;
}
/* Added here the linear gradient. From 0% to 100%. Use rgba for better results */
body::-webkit-scrollbar-track {
background: linear-gradient(0deg, #ee7752, #e73c7e 0%, #23a6d5, #23d5ab 100%);
border-color: black;
border-radius: 20px;
}
/* Added background: transparent */
body::-webkit-scrollbar-thumb {
background: transparent;
animation: scroll-gradient 5s ease infinite;
background-size: 100% 100%;
border-radius: 20px;
/* box shadow. If we set it to an enormous value with zero blur, it will cover all space around the scrollbar handle */
box-shadow: 0px 0px 0px 100000vh black;
}
/* You need this? I think no. */
/*::-webkit-scrollbar-thumb:hover {
background: #7333B1;
}*/
/*Changed size to view the changes*/
body {
height: 150vw;
}
<body>
<h1 style="height:200px">hello</h1>
</body>
I am currently making an animation that will apply a gradient mask on an image. The mask is a transparent mask and it will transform from right to left of the image. Here is my code.
<!DOCTYPE html>
<html>
<head>
<style>
.container {
height: 100vh;
width: 100vw;
background-color: white;
position: relative;
}
.first {
background-image: url('https://i.ibb.co/17zzm7P/flower.jpg');
background-size:cover;
position: absolute;
height: 100%;
width: 100%;
-webkit-mask-image: linear-gradient(to left, transparent 0px, black 20rem, black);
-webkit-animation: rightToLeft 5s forwards;
}
#keyframes rightToLeft {
0% {
-webkit-mask-position: 100vw 0%;
mask-position: 100vw 0%;
}
100% {
-webkit-mask-position: 0vw 0vw;
mask-position: 0vw 0vw;
}
}
</style>
</head>
<body>
<div class="container">
<div id="first" class="first"> </div>
</div>
</body>
</html>
Basically, the animation works well. However, the mask image is only applied to a specific area when it moves from right to left. Because the mask is transparent, I expect when it moves to the new area, the previous area it passed through is also transparent. How can I do to make the previous area transparent too?
Thank you so much for your time.
You are almost good, you only need to disable the repetition by using mask-repeat: no-repeat
.container {
height: 100vh;
background-color: white;
position: relative;
}
.first {
background-image: url('https://i.ibb.co/17zzm7P/flower.jpg');
background-size: cover;
position: absolute;
height: 100%;
width: 100%;
-webkit-mask-image: linear-gradient(to left, transparent, black 20rem);
-webkit-mask-repeat: no-repeat;
-webkit-animation: rightToLeft 5s forwards;
}
#keyframes rightToLeft {
0% {
-webkit-mask-position: 100vw 0%;
mask-position: 100vw 0%;
}
100% {
-webkit-mask-position: 0vw 0vw;
mask-position: 0vw 0vw;
}
}
body {
margin:0;
}
<div class="container">
<div id="first" class="first"> </div>
</div>
I'm currently doing a React app which shows what music I'm listening at that time. Obviously some of song names, album name etc. are longer than others so I want to show overflowing part with animation. I managed to do this and it's kinda okay. Longer text scrolls nicely but my problem is it also animates short texts and that causes some shaking on them during the animation.
Any ideas how to remove that shaking? Also Javascript based solutions are appreciated but this seemed to be shorter solution.
div {
width: 100px;
border: 1px solid black;
}
div p {
overflow: hidden;
white-space: nowrap;
display: inline-block;
position: relative;
min-width: 100%;
animation: 5s linear 0s infinite alternate scrolltext;
}
#keyframes scrolltext {
0%,
25% {
transform: translateX(0%);
left: 0%;
}
75%,
100% {
transform: translateX(-100%);
left: 100%;
}
}
<div>
<p>This is a very long text and rolls nicely</p>
<p>And these</p>
<p>two shaking?!</p>
</div>
use margin-left and margin-right instead of left and right
div {
width: 100px;
border: 1px solid black;
}
div p {
overflow: hidden;
white-space: nowrap;
display: inline-block;
position: relative;
min-width: 100%;
animation: 5s linear 0s infinite alternate scrolltext;
}
#keyframes scrolltext {
0%,
25% {
transform: translateX(0%);
margin-left: 0%;
}
75%,
100% {
transform: translateX(-100%);
margin-left: 100%;
}
}
<div>
<p>This is a very long text and rolls nicely</p>
<p>And these</p>
<p>two shaking?!</p>
</div>
div {
height: 41.4vmin;
width: 30vmin;
margin: 0.7vmin;
border-radius: 1.3vmin;
background-image: url("https://sun9-8.userapi.com/c840530/v840530203/60933/tkZK7aYQUjM.jpg");
background-size: contain;
}
#keyframes example {
0% {}
35% {background-image: url("https://sun9-8.userapi.com/c840530/v840530203/60933/tkZK7aYQUjM.jpg");}
36% {background-image: url("https://sun9-8.userapi.com/c840530/v840530203/6092c/fR8eCsT009k.jpg");}
100% {background-image: url("https://sun9-8.userapi.com/c840530/v840530203/6092c/fR8eCsT009k.jpg");transform: rotateY(160deg);}
}
div:hover {
animation-fill-mode: forwards;
animation-name: example;
animation-duration: 1s;
}
<div></div>
I don't use keyframes because i need set unique url for every animation. If i do this then need creator more 100 keyframes.
And i want to do this because with transition can set different url method js. But this not look how i want.
div {
height: 41.4vmin;
width: 30vmin;
margin: 0.7vmin;
border-radius: 1.3vmin;
background-image: url("https://sun9-8.userapi.com/c840530/v840530203/60933/tkZK7aYQUjM.jpg");
background-size: contain;
transition:
/* step 1 */
transform 1s,
/* step 2 */
background 0.0s 0.5s;
}
div:hover {
transform: rotateY(160deg);
background-image: url("https://sun9-8.userapi.com/c840530/v840530203/6092c/fR8eCsT009k.jpg");
}
<div></div>
My solution, you can create two elements front and back that lies inside card-container element and animate accordingly:
$(document).ready(function () {
$('.card-container').click(function () {
$(this).toggleClass('clicked');
});
});
.card-container {
position: relative;
overflow: hidden;
height: 41.4vmin;
width: 30vmin;
margin: 0.7vmin;
}
.card-container > div {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 1.3vmin;
transition: transform 1s, background 0.0s 0.5s;
transform-style: preserve-3d;
}
.card-container .front {
background-image: url("https://sun9-8.userapi.com/c840530/v840530203/60933/tkZK7aYQUjM.jpg");
background-size: contain;
background-color: black;
transform: rotateY(0deg);
}
.card-container .back {
background-image: url("https://sun9-8.userapi.com/c840530/v840530203/6092c/fR8eCsT009k.jpg");
background-size: contain;
transform: rotateY(180deg);
}
.card-container.clicked .front {
transform: rotateY(180deg);
}
.card-container.clicked .back {
transform: rotateY(0deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="card-container">
<div class="front"></div>
<div class="back"></div>
</div>
<div class="card-container">
<div class="front"></div>
<div class="back"></div>
</div>
Move the transition to the hover state and adjust the delay and you will have exactly the same thing:
div.card {
height: 41.4vmin;
width: 30vmin;
margin: 0.7vmin;
border-radius: 1.3vmin;
background-image: url("https://sun9-8.userapi.com/c840530/v840530203/60933/tkZK7aYQUjM.jpg");
background-size: contain;
}
div.card:hover {
transform: rotateY(160deg);
background-image: url("https://sun9-8.userapi.com/c840530/v840530203/6092c/fR8eCsT009k.jpg");
transition: transform 1s linear, background 0s 0.5s linear;
}
<div class="card"></div>
Why do you need 100 URL's to do this? You only need the front of the card image and the back of the card image.
img {
width:100%;
border:1px solid #e0e0e0;
border-radius:1vw;
}
.container {
/* Position and Size the Container */
position: absolute;
top: 17%;
bottom:0; /* Needed to keep the overall height larger than the card. */
left: 20%;
width: 25%;
/* Will inherit to children only (not all descendants) */
perspective: 900px;
}
#card .front {
/* Flip the front side of the card by rotating it around the y-axis. */
transform: rotateY(180deg);
}
#card:hover {
/* Rotate the card as a whole: */
transform: rotateY(180deg);
}
#card div {
/* Forces both elements to come out of the normal flow and occupy the same space on the page. */
position: absolute;
/*
The backface-visibility CSS property determines whether or not the back
face of the element is visible when facing the user. The back face of
an element is always a transparent background, letting, when visible,
a mirror image of the front face be displayed. If your foreground element
is opaque, this property may not need to be set.
*/
backface-visibility: hidden;
}
#card {
/*
Indicates that the children of the element should be positioned in the 3D-space.
And, pass any inherited perspective along to children.
*/
transform-style: preserve-3d;
/*
Changes to the transform property should take 1 second to
change from their current value to their new value.
*/
transition: transform 1s cubic-bezier(.75,1.25,.5,1.25);
}
<!-- The "container" will be the 3D space for us to work in. -->
<div class="container">
<!-- The "card" is the single entity that we will manipulate. -->
<div id="card">
<!-- The child elements make up pieces of the overall object.-->
<div class="front"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/Ace_of_spades.svg/2000px-Ace_of_spades.svg.png"></div>
<div class="back"><img src="https://thumb1.shutterstock.com/display_pic_with_logo/3172829/620603528/stock-vector-ace-of-spades-with-eyel-vintage-design-t-shirts-620603528.jpg"></div>
</div>
</div>
You'll need to use a transition-timing-function with palindromic timing, so the card image changeover can always be in the middle. Examples of this include linear or ease-in-out (incorporated below).
Note that some browsers don't support transition on background-image though, so you may need to approach this effect differently for it to work in IE, for example.
div {
height: 41.4vmin;
width: 30vmin;
margin: 0.7vmin;
border-radius: 1.3vmin;
background-image: url("https://sun9-8.userapi.com/c840530/v840530203/60933/tkZK7aYQUjM.jpg");
background-size: contain;
transition: transform 1s ease-in-out, background 0s .5s;
}
div:hover {
transform: rotateY(160deg);
background-image: url("https://sun9-8.userapi.com/c840530/v840530203/6092c/fR8eCsT009k.jpg");
}
<div></div>
I'm trying to imitate Twitter's notification animation
This is what i came up with so far:
$('button').click(function() {
$('#left').css('width', '400px');
$('#right').css('width', '400px');
});
.wrapper {
position: relative;
min-height: 50px;
}
.left {
position: absolute;
left: 0;
height: 50px;
background: #00AEEF;
}
.right {
position: absolute;
right: 0;
height: 50px;
background: #00AEEF;
}
.banner {
width: 0%;
overflow: hidden;
-webkit-transition: width 1s ease-in-out;
-moz-transition: width 1s ease-in-out;
-o-transition: width 1s ease-in-out;
transition: width 1s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div class="wrapper">
<div id="left" class="banner left"></div>
<div id="right" class="banner right"></div>
</div>
<div style="margin: 10px;">
<button>start animation</button>
</div>
</div>
But using 2 different divs for left and right animation feels like a hack.
Is there a nicer built-in css animation of that type (to be used on a single div)?
Sliding doors effect (only)
(see below for a full-effect demo)
You could animate the background-position of two linear-gradients placed in a single element (so you wouldn't even need to use two more empty elements for styling purpose) e.g.
div {
background:
linear-gradient(to left, #00AEEF 50%, transparent 0),
linear-gradient(to right, #00AEEF 50%, transparent 0);
background-position: 50vw 0, -50vw 0;
background-repeat: no-repeat;
height: 50px;
transition: background-position 1s;
}
:checked + div {
background-position: 0 0, 0 0;
}
Just set a class via js to trigger the transition (for the sake of simplicity I've activated the effect with a :checked pseudoclass)
Codepen demo
You could also obtain the same effect by the opposite animation: if you place a white gradient over a blue background-color you could animate just the background-size of the gradient like so
div {
background: #00AEEF linear-gradient(to right, #fff, #fff);
background-position: 50% 0;
background-repeat: no-repeat;
background-size: 100% 100%;
height: 50px;
transition: background-size 1s;
}
:checked ~ div { background-size: 0 100%; }
Codepen demo
Comparing the two approaches I personally prefer the last one (less code to type, one single gradient to be animated and it seems smoother. Furthermore, the second demo prevents an annoying rounding issue that sometimes happens in the first one, when repositioning the two gradients occurs, as you can see from the screenshot below)
Full effect (with all the animations/transitions)
To recreate the full effect of this notification, markup and style should of course slightly change: starting from the last demo, I moved the main effect on the <a> element inside the wrapper and I inserted other effects, like the # pulsing with an animation and the final slide down after 5 seconds.
The right arrow is made by the unicode symbol U+3009 and it is placed as the content of the a::after pseudoelement
Note: all properties are unprefixed. Add prefixes where necessary
Codepen Demo (Full effect)
Markup
<div class="notification">
<span>#</span>Miro mentioned you
</div>
CSS (embedding Lato font from google fonts)
* {
font : 1rem "Lato", Arial;
box-sizing : border-box;
}
.notification {
position : relative;
overflow : hidden;
font-weight : 100;
font-size : 1.5rem;
}
.notification a {
display : block;
padding : 1em 3em 1em 2.25em;
width : 100%;
font-size : inherit;
font-weight : inherit;
color : transparent;
background : #00AEEF linear-gradient(to right, #fff, #fff);
text-decoration : none;
background-position : 50% 0;
background-repeat : no-repeat;
background-size : 100% 100%;
}
/* The at-sign: I've also tried to use :first-letter but it
* is unreliable when the first char is not a letter or a digit
*/
.notification a span {
position : absolute;
line-height : 1;
top : 50%;
left : 50%;
color : #fff;
font-weight : bold;
transform : translate(-50%, -50%) scale(0);
transform-origin : 50% 50%;
}
/* The arrow */
.notification a:after {
position : absolute;
content : "\3009";
right : 1em;
top : 50%;
transform : translateY(-50%);
}
/* sliding doors effect, color change and final slide down
* all with proper delays
*/
:checked ~ .notification a {
transition: background-size .2s, color .33s 1s, transform 1s 5s;
transform: translateY(100%);
background-size: 0 100%;
color: #fff;
}
/* pulsing and moving the #-sign */
:checked ~ .notification a span {
animation: pulse-at .66s ease-in-out .33s forwards;
}
#keyframes pulse-at {
0% { transform: scale(0) translate(-50%, -50%); }
20% { transform: scale(1.1) translate(-50%, -50%); }
25% { transform: scale(1) translate(-50%, -50%); }
40% { transform: scale(1) translate(-50%, -50%); left: 50%; }
100% { transform: scale(1) translate(0, -50%); left: 1em; }
}
Final result