CSS - Animate object in curved path - html

I just want to animate my image through curved path. Like this way. ( I'm using position absolute for positioning. ) Did some research and found that css transform can do the job. It can be easily done by straight line. But curved path?
I tried to combine with css transform-origin + transform:rotate but I didn't get exact that I want. Clearly I want to move around 80% to the left curved and need to come to original position. I tried so many times adjusting my code but still no luck.
Fiddle
P.S
What is transform-origin really do here? Is it necessary?
Can someone explain me about how transform:rotate works here?
Here is my code
.sun{
width: 5.7%;
position: absolute;
top: -5%;
left: 57%;
animation: circle 10s linear infinite;
transform-origin: 0px 700px;
animation-fill-mode: forwards;
animation-direction: alternate;
}
#keyframes circle {
from {
transform:rotate(-60deg);
}
to {
transform:rotate(40deg);
}
}
<div class="sun">
<img src="sun.png" alt="">
</div>

Maybe make parent element move by rotate and children (in my case pseudoelement, whatever) make position absolute to the parent. And just use animation. Look at my solution. Maybe you will have to create some wrapper and use overflow: hidden, because it is square which is rotating. You can watch square's behavior by adding background-color.
#keyframes move-sun {
from {
transform: rotate(0deg);
}
to {
transform: rotate(90deg);
}
}
.sun {
position: relative;
width: 400px;
height: 400px;
margin: 200px;
transform: rotate(90deg);
animation: move-sun 10s;
}
.sun::before {
content: "";
position: absolute;
top: -25px;
left: -25px;
width: 50px;
height: 50px;
background-color: #ff0;
border-radius: 50%;
}
<div class="sun">
</div>

I realize this is an old question, but I just wanted to add another option. You could use 2 separate animations, one for the x-motion and one for the y-motion:
body {
background: #8DBECC;
}
.container {
position: relative;
height: 100%;
width: 100%;
}
.sun {
position: absolute;
width: 30px;
height: 200px;
animation: x-motion 3s ease-in-out 0s infinite alternate;
}
.sun:before {
content: '';
width: 30px;
height: 30px;
position: absolute;
top: 100%;
background: #F18C3E;
animation: y-motion 3s ease-in-out 0s infinite alternate;
border-radius: 15px;
}
#keyframes x-motion {
0% {
left: 0;
}
100% {
left: calc(100% - 30px);
}
}
#keyframes y-motion {
0%, 100% {
top: 100%;
}
50% {
top: 0%;
}
}
<html>
<body>
<div class="container">
<div class="sun">
</div>
</div>
</body>
</html>
https://jsfiddle.net/561pbt0r/27/

It might not be easy with CSS, but you can easily do this with SVG animation.
I modified a sample from this tutorial for your case:
<svg width="500" height="350" viewBox="0 0 350 350">
<path id="motionPath" fill="none" stroke="#000000" stroke-miterlimit="10" d="M100,100Q250,-50,400,100"/>
<g id="sun" transform="translate(-100, -300)">
<circle cx="100" cy="300" r="25" fill="yellow"/>
</g>
<animateMotion
xlink:href="#sun"
dur="3s"
begin="0s"
fill="freeze"
repeatCount="indefinite"
>
<mpath xlink:href="#motionPath" />
</animateMotion>
</svg>

When you want to apply some transform operation to an element, that transformation has a reference point from where it will be applied. That is the origin point and by default it is at the center of every element (i.e.: transform-origin(50% 50%)).
With this statement you can modify that origin whenever you need the transformation to apply from a different origin.
Here you can see an example when the rotation is done from the top left corner. Without the origin modification, it would rotate around its center.
Note: You can set the transform-origin even outside the element

Related

How to give hover effect to specific part of image?

For a project, I am trying to hover background colour change effect to specific part of image. Suppose I have this image
Now I want that when I hover over the orange on the right side I the background glow should change. Similarly I can do it for the other items in the image.
I could not find any property where I can specify coordinates of the image where hover effect can be applied to.
Is there any way this is possible? Any pre processing through photoshop or some software that might help?
edit: by background glow I mean using drop-shadow(16px 16px 20px red);property
I've made you an example with just the right-most orange, but you get the idea. just place SVGs and give each a unique class name (for size/position).
You can use an online tool, such as this, to create your SVG shapes.
A thing to keep in mind is if the image resizes, the position & size of the highlights should remain correct (this is why working with percentages is best)
.imageWrapper {
width: 500px;
position: relative;
}
.imageWrapper img {
width:100%; height:100%;
object-fit: contain;
}
.image-area {
position: absolute;
top: 69.5%; /* position should be in percentages */
left: 73.5%; /* position should be in percentages */
transition: .4s;
mix-blend-mode: lighten; /* work the best with the default black fill of svg shapes */
cursor: pointer;
}
.image-area:hover {
filter: drop-shadow(0 0 20px gold);
}
.image-area--orange-1 {
/* sizes should be in percentages */
width: 21%;
height: 18%;
}
<div class='imageWrapper'>
<!-- fill with SVG areas -->
<svg viewBox="0 0 100 100" class='image-area image-area--orange-1'>
<circle cx="50" cy="50" r="50"/>
</svg>
<!-- -->
<img src="https://i.stack.imgur.com/8BVo6.jpg"/>
</div>
Please consider using the image region mapping, this should be standard for most browser and don't need image manipulation
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/map
const circleClip = document.querySelector("#bg");
function removeIntro() {
circleClip.classList.remove("intro");
}
function circleMove(e) {
removeIntro();
circleClip.style.setProperty("--x", e.clientX + "px");
circleClip.style.setProperty("--y", e.clientY + "px");
}
document.addEventListener("mousemove", circleMove);
circleClip.addEventListener("touchmove", (e) => {
removeIntro();
let touch = e.touches[0];
e.preventDefault();
circleClip.style.setProperty("--x", touch.clientX + "px");
circleClip.style.setProperty("--y", touch.clientY + "px");
});
:root {
--x: 0px;
--y: 0px;
}
body {
position: relative;
margin: 0;
overflow: hidden;
background-image: url(https://i.stack.imgur.com/8BVo6.jpg);
background-size: 100% 35%;
backdrop-filter: grayscale(100%);
}
#bg {
position: relative;
background: url(https://i.stack.imgur.com/8BVo6.jpg) no-repeat;
background-size: 100% 35%;
min-height: 300vh;
clip-path: circle(10% at var(--x) var(--y));
}
#bg.intro {
clip-path: circle(100% at 50% 50%);
animation: circleIntro 1800ms cubic-bezier(0.645, 0.045, 0.355, 1) both;
}
#keyframes circleIntro {
100% {
clip-path: circle(10% at 50% 50%);
}
}
<div id="bg" class="intro"></div>

Create line loading animation using css

Hey i have tried animation on a 2px solid line that fill white color from center to its end but failed because it just filled right to left and not gained from direction inverse.
Can any body tells me how to create the animation that work like this:
This is just the structure. The 2px height and 100px width just from the point + and fill the color from center to the ends in equal length from left and right and complete this type of animation. Hope I had explained my question with detail.
[----------+----------]
[---------+++---------]
[--------+++++--------]
[-------+++++++-------]
[------+++++++++------]
[-----+++++++++++-----]
[----+++++++++++++----]
[---+++++++++++++++---]
[--+++++++++++++++++--]
[-+++++++++++++++++++-]
[+++++++++++++++++++++]
something like below:
.line {
width:100px;
height:2px;
background:linear-gradient(red 0 0) center/0% 100% no-repeat;
animation:l 2s linear infinite alternate;
}
#keyframes l {
to {background-size:100% 100%}
}
<div class="line"></div>
Solution with stroke-dasharray
A line 100px long is drawn from the center with two rays.
Before starting animation stroke-dasharray: 0.50 0.50; both rays have
a dash equal to zero, and the maximum gap length is 50px. Therefore,
the line is initially invisible.
At the end of the animation, the gap of both rays become equal to
zero, and the dash takes on a maximum value of 100px, so the line
becomes fully visible
#pol{
fill:none;
stroke:red;
stroke-width:2;
stroke-dasharray:0,50 0,50;
animation:mid 2s linear infinite alternate;
}
#keyframes mid {
to {stroke-dasharray:0,0,100,0;}
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="200" height="200" viewBox="0 0 200 200" >
<polyline id="pol" stroke-dasharray="0,100" points="50,50 150,50" >
</polyline>
<text x="100" y="46" font-size="24px" text-anchor="middle" fill="black"> animate</text>
</svg>
The trick here for making from center to left is decreasing margin-left in animation
.wrapper {
position: relative;
width: 200px;
height: 2px;
background-color: #000000;
}
#inner-right,
#inner-left {
width: 0;
height: 100%;
background: white;
}
#inner-left {
margin-left: 50%;
animation: centerToLeft 2000ms ease forwards infinite;
}
#inner-right {
position: absolute;
top: 0;
left: 50%;
animation: centerToRight 2000ms ease forwards infinite;
}
#keyframes centerToRight {
to {
width: 50%;
}
}
#keyframes centerToLeft {
to {
margin-left: 0;
width: 50%;
}
}
<div class="wrapper">
<div id="inner-left"></div>
<div id="inner-right"></div>
</div>

Spinning Svg vs Html element - not spining on axis [duplicate]

This question already has answers here:
Why is blue circle not spinning in the center of itself [duplicate]
(2 answers)
Closed 2 years ago.
I am wanting to create a logo with a spinning icon in the centre. I have a few paths in it, and just want to spin one of the paths, that i have named on its central axis. I found many examples online, but couldn't get it to spin on its central axis.
I then have now simplified it to the following code pen.
If I spin a simple div, this works fine.
However if I try to spin a path inside an svg, it does not spin correctly.
What am I missing?
<html>
<head>
<style>
#keyframes spin {
from {transform:rotate(0deg);}
to {transform:rotate(360deg);}
}
rect {
animation: spin 2s infinite linear;
}
#rect{
width: 100px;
height: 100px;
animation: spin 2s infinite linear;
}
</style>
</head>
<body>
<div id="rect" style="background-color: blue; border: solid thin black;"></div>
<svg xmlns="http://www.w3.org/2000/svg">
<rect width='100' height='100' fill="green" stroke="black" />
</svg>
</body>
</html>
codepen
Add this selector with your <style>...</style> tag:
svg {
width: 100px;
height: 100px;
overflow: overlay;
}
Also, override the default transform-origin rule for rect:
rect {
...
transform-origin: unset;
}
<html>
<head>
<style>
#keyframes spin {
from {transform:rotate(0deg);}
to {transform:rotate(360deg);}
}
svg {
width: 100px;
height: 100px;
overflow: overlay;
}
rect {
animation: spin 2s infinite linear;
transform-origin: unset;
}
#rect {
width: 100px;
height: 100px;
animation: spin 2s infinite linear;
}
</style>
</head>
<body>
<div id="rect" style="background-color: blue; border: solid thin black;"></div>
<svg xmlns="http://www.w3.org/2000/svg">
<rect width='100' height='100' fill="green" stroke="black" />
</svg>
</body>
</html>

Using CSS3 turn triangle into square with animation on hover

I am trying to develop a CSS box hover effect using HTML5 & CSS3 but I cannot get this to work. I would like to make an effect like seen below:
when the user is not hovering
when user is hovering
i.e. how can I make a blue triangle and turn it into a blue square when the user hovers over it using HTML5 and CSS3? I need this only using HTML5 & CSS3 and not using canvas.
This element work with canvas perfectly like as below
var ctx = document.getElementById("c").getContext("2d");
ctx.fillStyle = "#0000ff";
function normal() {
ctx.clearRect(0,0,256,256);
ctx.beginPath();
ctx.moveTo(256,256);
ctx.lineTo(256,0);
ctx.lineTo(0,0);
ctx.closePath();
ctx.fill(); bars()
ctx.fillStyle="#0000ff"; for (i=0;i
But I need only using HTML5 & CSS3 scripting languages
Using SVG: (the entire effect that you are looking for)
I know you've asked for HTML(5) + CSS(3) but you could also use a SVG path element to produce this effect like in the below snippet. (Note: This uses SVG animations and its browser support can be different compared to CSS animations.)
svg {
height: 150px;
width: 150px;
stroke: black;
}
#blue {
stroke: blue;
stroke-width: 10;
}
svg polygon {
fill: blue;
}
#white {
stroke: white;
stroke-width: 10;
}
#icon {
fill: transparent;
}
<svg viewBox='0 0 100 100'>
<defs>
<clipPath id='clipper' clipPathUnits='objectBoundingBox'>
<path d='M0,0 1,0 1,1 0,0z'>
<animate attributeType="XML" attributeName="d" from="M0,0 1,0 1,1 0,0z" to="M0,0 1,0 1,1 0,1z" dur="1s" begin="icon.mouseover" fill="freeze" />
<animate attributeType="XML" attributeName="d" from="M0,0 1,0 1,1 0,1z" to="M0,0 1,0 1,1 0,0z" dur="1s" begin="icon.mouseout" fill="freeze" />
</path>
</clipPath>
<g id='lines'>
<line x1='20' y1='30' x2='80' y2='30' />
<line x1='20' y1='50' x2='80' y2='50' />
<line x1='20' y1='70' x2='80' y2='70' />
</g>
</defs>
<use xlink:href='#lines' id='blue' />
<g clip-path='url(#clipper)'>
<polygon points='0,0 0,100 100,100 100,0' />
<use xlink:href='#lines' id='white' />
</g>
<g>
<polygon points='0,0 0,100 100,100 100,0' id='icon' />
</g>
</svg>
The below are answers to the question - how to turn triangle into square with animation.
Using Borders:
You could do it using border like in the below snippet. Initially only the right and top borders have the blue color but on hover we set the color to all border sides. This method is pretty simple and will work in all browsers (including IE8) but you cannot add content directly to this div (as doing so will affect the triangle shape) and so you'd have to place content on top of the shape using positioning or set the shape using a pseudo-element.
.shape{
height: 0px;
width: 0px;
border: 50px solid transparent;
border-color: blue blue transparent transparent;
transition: all 1s;
}
.shape:hover{
border-color: blue;
}
<div class='shape'></div>
Using Transforms:
You could add rotate transform on a pseudo-element, set overflow: hidden on parent to produce the triangle and then reverse/nullify the transform on hover.
.shape {
position: relative;
height: 100px;
width: 100px;
overflow: hidden;
}
.shape:after {
position: absolute;
content: '';
height: calc(100% * 1.414); /* using Pythogras theorem */
width: calc(100% * 1.414); /* using Pythogras theorem */
transform: rotate(-45deg);
transform-origin: left top;
background: blue;
transition: all 1s;
}
.shape:hover:after {
transform: rotate(0deg);
}
<div class='shape'></div>
You could also use a skewX transform instead of a rotate transform if you wish to avoid calculating the height and width like in the previous snippet.
.shape {
position: relative;
height: 100px;
width: 100px;
overflow: hidden;
}
.shape:after {
position: absolute;
content: '';
height: 100%;
width: 100%;
transform: skewX(45deg);
transform-origin: left top;
background: blue;
transition: all 1s;
}
.shape:hover:after {
transform: skewX(0deg);
}
<div class='shape'></div>
Using Gradients:
You could use linear-gradients to create a triangle and then turn it into a square on hover by doubling the background-size.
.shape{
height: 100px;
width: 100px;
background: linear-gradient(to bottom left, blue 49.5%, transparent 50.5%);
background-position: 100% 0%;
background-size: 100% 100%;
transition: all 1s;
}
.shape:hover{
background-size: 200% 200%; /* just double the background size on hover */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='shape'></div>
In spite of the complete answer from Harry, couldn't resist to post an answer with another approach, suggested by the image in the OP.
Let's use blend modes, and see what can be achieved (but with more limited support)
.test {
width: 200px;
height: 200px;
background-color: white;
display: inline-block;
background-image: linear-gradient(blue, blue), linear-gradient(blue, blue), linear-gradient(blue, blue);
background-size: 100px 30px;
background-repeaT: no-repeat;
background-position: center 30px, center center, center 140px;
border: solid 1px black;
position: relative;
overflow: hidden;
}
.test:after {
content: "";
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
background: linear-gradient(45deg, yellow 50%, transparent 50%);
mix-blend-mode: difference;
transition: all 1s;
}
.one:after {
transform-origin: bottom right;
}
.one:hover:after {
transform: rotate(-45deg);
}
.two:hover:after {
opacity: 0;
}
.three:after {
background: none;
box-shadow: -1000px 1000px 0px 1000px yellow;
transform-origin: top left;
transform: rotate3d(1,1,0,87deg);
}
.three:hover:after {
transform: rotate3d(1,1,0,0deg);
}
<div class="test one"></div>
<div class="test two"></div>
<div class="test three"></div>
the third one is a little bit tricky, and not quite perfect. But you get the idea.

using svg line to imitate border of div

The end goal of this
use svg line to underscore border of div that contains it
webkit animation effects dash forwards to imitate border effects
If possible, the line to "be" the top border of the div
The problem is the extra padding below the top of the containing div. I do not know the source of the padding. Any tries at top: 0; or margin: 0; are unsuccessful.
Actual Results
The line is affected by unknown padding and pushed down a bit
I have an svg line with a div that contains it. This all happens in the ...
HTML
<div style = "display: inline;" id="divDisplay">
<svg height="1" width="1500">
<line id="top" x1="0" y1="0" x2="1500" y2="0" />
</svg>
</div>
CSS
#divDisplay {
background:linear-gradient(to bottom, #8dd2d9 , #58c0c7);
border: 2px solid #dadada;
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #111;
height: 100px;
}
#top {
top: 0;
position: fixed;
margin:0;
stroke: rgb(112,111,111);
stroke-width: 5;
stroke-dasharray:1300;
stroke-dashoffset:1300;
-webkit-animation: dash-top 3.00s forwards;
}
#-webkit-keyframes dash-top {
to { stroke-dashoffset: 0; }
}
This is because the <svg> element is inline by default, so vertical-align applies and defaults to baseline.
A quick fix is to change the vertical-align value: updated fiddle
svg {
vertical-align: top;
}
Not sure about the root cause, but adding the following css solved it.
#divDisplay svg
{
position:absolute;
top:1;
}
http://jsfiddle.net/wmeLa8tc/