I am trying to achieve something like this for my React Native project.
I have tried using css-to-react-native-transform library to convert CSS to JS but it's been unsuccessful so far.
So any help regarding this issue would be greatly appreciated as I am fairly new with this.
Here is the CSS code:
<style>
.waves {
position: absolute;
bottom: 4.5vh;
width: 100%;
height:15vh;
margin-bottom:-7px; Fix for safari gap
min-height:130px;
max-height:180px;
}
/* Animation */
.parallax > use {
animation: move-forever 25s cubic-bezier(.55,.5,.45,.5) infinite;
}
.parallax > use:nth-child(1) {
animation-delay: -2s;
animation-duration: 7s;
}
.parallax > use:nth-child(2) {
animation-delay: -3s;
animation-duration: 10s;
}
.parallax > use:nth-child(3) {
animation-delay: -4s;
animation-duration: 13s;
}
.parallax > use:nth-child(4) {
animation-delay: -5s;
animation-duration: 20s;
}
#keyframes move-forever {
0% {
transform: translate3d(-90px,0,0);
}
100% {
transform: translate3d(85px,0,0);
}
}
/Shrinking for mobile/
#media (max-width: 768px) {
.waves {
height:70px;
min-height:70px;
}
}
</style>
<!--Waves Container-->
<div>
<svg class="waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 24 150 28" preserveAspectRatio="none" shape-rendering="auto">
<defs>
<path id="gentle-wave" d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z" />
</defs>
<g class="parallax">
<use xlink:href="#gentle-wave" x="48" y="0" fill="rgba(255,255,255,0.7" />
<use xlink:href="#gentle-wave" x="48" y="3" fill="#89c2ee" />
<use xlink:href="#gentle-wave" x="48" y="5" fill="#0379ff" />
<use xlink:href="#gentle-wave" x="48" y="7" fill="#fff" />
</g>
</svg>
</div>
<!--Waves end-->
Here is what I have tried so far on my React Native:
import React from 'react';
import { View, Image, StyleSheet, ImageBackground, Text } from 'react-native';
import { useTheme } from 'react-native-paper';
import { SCREEN_INFO } from './constants';
import transform from "css-to-react-native-transform";
const color = transform(`
.waves {
position: absolute;
bottom: 4.5vh;
width: 100%;
height:15vh;
margin-bottom:-7px;
min-height:130px;
max-height:180px;
}
.parallax > use {
animation: move-forever 25s cubic-bezier(.55,.5,.45,.5) infinite;
}
.parallax > use:nth-child(1) {
animation-delay: -2s;
animation-duration: 7s;
}
.parallax > use:nth-child(2) {
animation-delay: -3s;
animation-duration: 10s;
}
.parallax > use:nth-child(3) {
animation-delay: -4s;
animation-duration: 13s;
}
.parallax > use:nth-child(4) {
animation-delay: -5s;
animation-duration: 20s;
}
#keyframes move-forever {
0% {
transform: translate3d(-90px,0,0);
}
100% {
transform: translate3d(85px,0,0);
}
}
#media (max-width: 768px) {
.waves {
height:70px;
min-height:70px;
}
}
`);
export default function Welcome({ navigation, route }) {
const { colors } = useTheme();
return (
<View
style={styles.flex}
>
<View style={{borderWidth: 2, borderColor: 'red'}}>
<View style={[styles.waves]}/>
<View style={styles.parallax}/>
<Text style={{fontSize: 20, color:'black'}}>Hello</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
flex: {
flex: 1,
},
center: {
justifyContent: 'center',
alignItems: 'center',
flex: 1,
}
});
Related
I was trying to use SVGs to animate the logo for my personal website, but it's not working entirely as expected. In my CSS, I used stroke-dasharray and stroke-dashoffset to animate the SVG. But as you can see in the picture below, it's not "completing" the path and finishing outlining the logo.
It may not seem like a big deal but it is really noticeable on mobile devices.
I've checked to make sure that the actual SVG code is fine, which it is, and I've tried playing around with the values for the stroke-dasharray and stroke-dashoffset in the CSS but nothing seems to work.
Here is the code that I took from out of my website (also on JSFiddle at https://jsfiddle.net/jgpixel/ehkum9vx/7/):
class Component {
constructor(props, root) {
this.props = props;
this.root = root;
}
static setAttributes(attributes, element) {
for (const key in attributes) {
element.setAttribute(key, attributes[key]);
}
}
}
class WebsiteLoader extends Component {
constructor(props, root) {
super(props, root);
this.render();
}
render() {
document.body.className = 'no-scroll';
const overlay = document.createElement('div');
overlay.className = 'overlay';
const overlayContent = document.createElement('div');
overlayContent.className = 'overlay-content';
const jgLogo = this.createSVGLogo();
this.root.appendChild(overlay);
overlay.appendChild(overlayContent);
overlayContent.appendChild(jgLogo);
setTimeout(() => {
overlay.classList.add('fade-out-overlay');
document.body.classList.remove('no-scroll');
setTimeout(() => {
overlay.remove();
}, 410);
}, this.props.animationDuration);
}
createSVGLogo() {
const iconSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
Component.setAttributes({
'width': 166,
'height': 73,
'viewBox': '0 0 166 73',
'fill': 'none'
}, iconSVG);
const pixelPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
Component.setAttributes({
'class': 'pixel',
'd': 'M161.63 57.4413L161.649 57.4609L161.669 57.4799C163.25 59.0047 164.01 60.7848 164.01 62.9001C164.01 65.0173 163.248 66.8409 161.649 68.4394C160.129 69.9597 158.344 70.7001 156.21 70.7001C154.084 70.7001 152.261 69.9639 150.671 68.4392C149.146 66.8494 148.41 65.0262 148.41 62.9001C148.41 60.7668 149.151 58.981 150.671 57.4608C152.269 55.8622 154.093 55.1001 156.21 55.1001C158.325 55.1001 160.106 55.86 161.63 57.4413Z',
'stroke': '#FF656F',
'stroke-width': 3
}, pixelPath);
const letterPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
Component.setAttributes({
'class': 'jg',
'd': 'M1.86963 51.4062L14.9914 46.5371C16.3136 50.0457 18.032 52.8129 20.2098 54.7267C22.7214 56.9339 25.8559 58 29.5 58C33.6001 58 37.0432 56.6285 39.6897 53.8308C42.3327 51.0368 43.6 47.4105 43.6 43.1V2.6H57.8V43.6C57.8 49.0361 56.5873 53.7306 54.2102 57.7342L54.2058 57.7417L54.2014 57.7492C51.8783 61.7675 48.6188 64.9065 44.39 67.1787C40.1784 69.4416 35.1976 70.6 29.4 70.6C22.2609 70.6 16.3535 68.8365 11.5886 65.3915C7.20853 62.1181 3.95558 57.4855 1.86963 51.4062ZM121.82 44.1H104.42V32.2H138.92V35.7C138.92 40.7926 138.051 45.4669 136.329 49.7393L136.325 49.7502C134.661 53.9727 132.3 57.6722 129.238 60.8612L129.238 60.8617C126.253 63.9734 122.694 66.3912 118.545 68.1148C114.41 69.8322 109.875 70.7 104.92 70.7C99.8313 70.7 95.1235 69.8316 90.7823 68.1092C86.4218 66.3125 82.5846 63.849 79.2599 60.7186C76.0023 57.5223 73.4496 53.8524 71.5957 49.7013C69.816 45.5012 68.9203 40.9727 68.9203 36.1C68.9203 31.2241 69.8171 26.7293 71.5958 22.5983C73.4543 18.3703 75.9789 14.6988 79.1702 11.5713L79.1704 11.5711C82.4245 8.38083 86.2212 5.92237 90.5739 4.19412L90.5827 4.19063L90.5914 4.18702C94.9328 2.3994 99.6042 1.5 104.62 1.5C110.338 1.5 115.721 2.68692 120.784 5.0584L120.791 5.06171L120.798 5.06496C125.403 7.16338 129.214 9.99044 132.254 13.5424L122.384 22.4334C120.227 19.9485 117.762 18.014 114.985 16.6555C111.829 15.0787 108.366 14.3 104.62 14.3C101.628 14.3 98.8221 14.8705 96.2204 16.0251C93.7149 17.1003 91.4919 18.6071 89.5597 20.5393L89.5497 20.5493L89.5398 20.5595C87.6654 22.5061 86.1973 24.8042 85.1302 27.4364L85.1236 27.4527L85.1174 27.4692C84.1131 30.1234 83.6203 33.0056 83.6203 36.1C83.6203 39.2072 84.1507 42.1289 85.2251 44.8507L85.225 44.8508L85.2302 44.8636C86.3003 47.503 87.804 49.8329 89.7406 51.8412L89.7595 51.8608L89.7791 51.8798C91.7733 53.8028 94.0533 55.3339 96.6111 56.4707L96.6338 56.4808L96.6568 56.4901C99.3159 57.5681 102.175 58.1 105.22 58.1C108.123 58.1 110.791 57.6043 113.199 56.584C115.643 55.5765 117.751 54.163 119.502 52.3388C121.258 50.5105 122.514 48.4099 123.252 46.0474L123.861 44.1H121.82Z',
'stroke': 'white',
'stroke-width': 3
}, letterPath);
iconSVG.appendChild(letterPath);
iconSVG.appendChild(pixelPath);
return iconSVG;
}
}
new WebsiteLoader({
animationDuration: 6500
}, document.getElementById('root'))
:root {
--primary: #0F1F39;
--accent: #FF656F;
--type: #FFFFFF;
}
html,
body {
min-height: 100%;
background-color: var(--primary);
color: var(--type);
margin: 0;
padding: 0;
}
body.no-scroll {
overflow: hidden;
}
.overlay {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
z-index: 9999999;
display: flex;
justify-content: center;
align-items: center;
animation: hideOverlay;
animation-duration: 1s;
animation-fill-mode: forwards;
background-color: var(--primary);
}
.overlay-content {
display: flex;
}
.overlay-content {
font-size: 100px;
font-weight: bold;
}
.fade-out-overlay {
animation: fadeOutOverlay;
animation-duration: 0.4s;
animation-fill-mode: forwards;
}
#keyframes fadeOutOverlay {
to {
opacity: 0;
}
}
.jg {
stroke-dasharray: 395px;
stroke-dashoffset: 395px;
animation: drawLetter 4s forwards,
fillLetter 0.3s 4.5s forwards;
}
.pixel {
stroke-dasharray: 49px;
stroke-dashoffset: 49px;
animation:drawPixel 4s forwards,
fillPixel 0.3s 4.5s forwards;
}
.jg,
.pixel {
fill: transparent;
}
#keyframes drawLetter {
to {
stroke-dashoffset: 0;
}
}
#keyframes fillLetter {
to {
fill: var(--type);
}
}
#keyframes drawPixel {
to {
stroke-dashoffset: 0;
}
}
#keyframes fillPixel {
to {
fill: var(--accent);
}
}
<div id="root"></div>
Also, here is the code for the SVG, which I've given a background color to just for demonstration purposes (so the white is visible):
<svg width="166" height="73" viewBox="0 0 166 73" fill="none" style="background-color: #0F1F39" xmlns="http://www.w3.org/2000/svg">
<path d="M161.63 57.4413L161.649 57.4609L161.669 57.4799C163.25 59.0047 164.01 60.7848 164.01 62.9001C164.01 65.0173 163.248 66.8409 161.649 68.4394C160.129 69.9597 158.344 70.7001 156.21 70.7001C154.084 70.7001 152.261 69.9639 150.671 68.4392C149.146 66.8494 148.41 65.0262 148.41 62.9001C148.41 60.7668 149.151 58.981 150.671 57.4608C152.269 55.8622 154.093 55.1001 156.21 55.1001C158.325 55.1001 160.106 55.86 161.63 57.4413Z" stroke="#FF656F" stroke-width="3"/>
<path d="M1.86963 51.4062L14.9914 46.5371C16.3136 50.0457 18.032 52.8129 20.2098 54.7267C22.7214 56.9339 25.8559 58 29.5 58C33.6001 58 37.0432 56.6285 39.6897 53.8308C42.3327 51.0368 43.6 47.4105 43.6 43.1V2.6H57.8V43.6C57.8 49.0361 56.5873 53.7306 54.2102 57.7342L54.2058 57.7417L54.2014 57.7492C51.8783 61.7675 48.6188 64.9065 44.39 67.1787C40.1784 69.4416 35.1976 70.6 29.4 70.6C22.2609 70.6 16.3535 68.8365 11.5886 65.3915C7.20853 62.1181 3.95558 57.4855 1.86963 51.4062ZM121.82 44.1H104.42V32.2H138.92V35.7C138.92 40.7926 138.051 45.4669 136.329 49.7393L136.325 49.7502C134.661 53.9727 132.3 57.6722 129.238 60.8612L129.238 60.8617C126.253 63.9734 122.694 66.3912 118.545 68.1148C114.41 69.8322 109.875 70.7 104.92 70.7C99.8313 70.7 95.1235 69.8316 90.7823 68.1092C86.4218 66.3125 82.5846 63.849 79.2599 60.7186C76.0023 57.5223 73.4496 53.8524 71.5957 49.7013C69.816 45.5012 68.9203 40.9727 68.9203 36.1C68.9203 31.2241 69.8171 26.7293 71.5958 22.5983C73.4543 18.3703 75.9789 14.6988 79.1702 11.5713L79.1704 11.5711C82.4245 8.38083 86.2212 5.92237 90.5739 4.19412L90.5827 4.19063L90.5914 4.18702C94.9328 2.3994 99.6042 1.5 104.62 1.5C110.338 1.5 115.721 2.68692 120.784 5.0584L120.791 5.06171L120.798 5.06496C125.403 7.16338 129.214 9.99044 132.254 13.5424L122.384 22.4334C120.227 19.9485 117.762 18.014 114.985 16.6555C111.829 15.0787 108.366 14.3 104.62 14.3C101.628 14.3 98.8221 14.8705 96.2204 16.0251C93.7149 17.1003 91.4919 18.6071 89.5597 20.5393L89.5497 20.5493L89.5398 20.5595C87.6654 22.5061 86.1973 24.8042 85.1302 27.4364L85.1236 27.4527L85.1174 27.4692C84.1131 30.1234 83.6203 33.0056 83.6203 36.1C83.6203 39.2072 84.1507 42.1289 85.2251 44.8507L85.225 44.8508L85.2302 44.8636C86.3003 47.503 87.804 49.8329 89.7406 51.8412L89.7595 51.8608L89.7791 51.8798C91.7733 53.8028 94.0533 55.3339 96.6111 56.4707L96.6338 56.4808L96.6568 56.4901C99.3159 57.5681 102.175 58.1 105.22 58.1C108.123 58.1 110.791 57.6043 113.199 56.584C115.643 55.5765 117.751 54.163 119.502 52.3388C121.258 50.5105 122.514 48.4099 123.252 46.0474L123.861 44.1H121.82Z" stroke="white" stroke-width="3"/>
</svg>
Thanks for the help in advance.
Add stroke-linecap: square:
class Component {
constructor(props, root) {
this.props = props;
this.root = root;
}
static setAttributes(attributes, element) {
for (const key in attributes) {
element.setAttribute(key, attributes[key]);
}
}
}
class WebsiteLoader extends Component {
constructor(props, root) {
super(props, root);
this.render();
}
render() {
document.body.className = 'no-scroll';
const overlay = document.createElement('div');
overlay.className = 'overlay';
const overlayContent = document.createElement('div');
overlayContent.className = 'overlay-content';
const jgLogo = this.createSVGLogo();
this.root.appendChild(overlay);
overlay.appendChild(overlayContent);
overlayContent.appendChild(jgLogo);
setTimeout(() => {
overlay.classList.add('fade-out-overlay');
document.body.classList.remove('no-scroll');
setTimeout(() => {
overlay.remove();
}, 410);
}, this.props.animationDuration);
}
createSVGLogo() {
const iconSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
Component.setAttributes({
'width': 166,
'height': 73,
'viewBox': '0 0 166 73',
'fill': 'none'
}, iconSVG);
const pixelPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
Component.setAttributes({
'class': 'pixel',
'd': 'M161.63 57.4413L161.649 57.4609L161.669 57.4799C163.25 59.0047 164.01 60.7848 164.01 62.9001C164.01 65.0173 163.248 66.8409 161.649 68.4394C160.129 69.9597 158.344 70.7001 156.21 70.7001C154.084 70.7001 152.261 69.9639 150.671 68.4392C149.146 66.8494 148.41 65.0262 148.41 62.9001C148.41 60.7668 149.151 58.981 150.671 57.4608C152.269 55.8622 154.093 55.1001 156.21 55.1001C158.325 55.1001 160.106 55.86 161.63 57.4413Z',
'stroke': '#FF656F',
'stroke-width': 3
}, pixelPath);
const letterPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
Component.setAttributes({
'class': 'jg',
'd': 'M1.86963 51.4062L14.9914 46.5371C16.3136 50.0457 18.032 52.8129 20.2098 54.7267C22.7214 56.9339 25.8559 58 29.5 58C33.6001 58 37.0432 56.6285 39.6897 53.8308C42.3327 51.0368 43.6 47.4105 43.6 43.1V2.6H57.8V43.6C57.8 49.0361 56.5873 53.7306 54.2102 57.7342L54.2058 57.7417L54.2014 57.7492C51.8783 61.7675 48.6188 64.9065 44.39 67.1787C40.1784 69.4416 35.1976 70.6 29.4 70.6C22.2609 70.6 16.3535 68.8365 11.5886 65.3915C7.20853 62.1181 3.95558 57.4855 1.86963 51.4062ZM121.82 44.1H104.42V32.2H138.92V35.7C138.92 40.7926 138.051 45.4669 136.329 49.7393L136.325 49.7502C134.661 53.9727 132.3 57.6722 129.238 60.8612L129.238 60.8617C126.253 63.9734 122.694 66.3912 118.545 68.1148C114.41 69.8322 109.875 70.7 104.92 70.7C99.8313 70.7 95.1235 69.8316 90.7823 68.1092C86.4218 66.3125 82.5846 63.849 79.2599 60.7186C76.0023 57.5223 73.4496 53.8524 71.5957 49.7013C69.816 45.5012 68.9203 40.9727 68.9203 36.1C68.9203 31.2241 69.8171 26.7293 71.5958 22.5983C73.4543 18.3703 75.9789 14.6988 79.1702 11.5713L79.1704 11.5711C82.4245 8.38083 86.2212 5.92237 90.5739 4.19412L90.5827 4.19063L90.5914 4.18702C94.9328 2.3994 99.6042 1.5 104.62 1.5C110.338 1.5 115.721 2.68692 120.784 5.0584L120.791 5.06171L120.798 5.06496C125.403 7.16338 129.214 9.99044 132.254 13.5424L122.384 22.4334C120.227 19.9485 117.762 18.014 114.985 16.6555C111.829 15.0787 108.366 14.3 104.62 14.3C101.628 14.3 98.8221 14.8705 96.2204 16.0251C93.7149 17.1003 91.4919 18.6071 89.5597 20.5393L89.5497 20.5493L89.5398 20.5595C87.6654 22.5061 86.1973 24.8042 85.1302 27.4364L85.1236 27.4527L85.1174 27.4692C84.1131 30.1234 83.6203 33.0056 83.6203 36.1C83.6203 39.2072 84.1507 42.1289 85.2251 44.8507L85.225 44.8508L85.2302 44.8636C86.3003 47.503 87.804 49.8329 89.7406 51.8412L89.7595 51.8608L89.7791 51.8798C91.7733 53.8028 94.0533 55.3339 96.6111 56.4707L96.6338 56.4808L96.6568 56.4901C99.3159 57.5681 102.175 58.1 105.22 58.1C108.123 58.1 110.791 57.6043 113.199 56.584C115.643 55.5765 117.751 54.163 119.502 52.3388C121.258 50.5105 122.514 48.4099 123.252 46.0474L123.861 44.1H121.82Z',
'stroke': 'white',
'stroke-width': 3
}, letterPath);
iconSVG.appendChild(letterPath);
iconSVG.appendChild(pixelPath);
return iconSVG;
}
}
new WebsiteLoader({
animationDuration: 6500
}, document.getElementById('root'))
:root {
--primary: #0F1F39;
--accent: #FF656F;
--type: #FFFFFF;
}
html,
body {
min-height: 100%;
background-color: var(--primary);
color: var(--type);
margin: 0;
padding: 0;
}
body.no-scroll {
overflow: hidden;
}
.overlay {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
z-index: 9999999;
display: flex;
justify-content: center;
align-items: center;
animation: hideOverlay;
animation-duration: 1s;
animation-fill-mode: forwards;
background-color: var(--primary);
}
.overlay-content {
display: flex;
}
.overlay-content {
font-size: 100px;
font-weight: bold;
}
.fade-out-overlay {
animation: fadeOutOverlay;
animation-duration: 0.4s;
animation-fill-mode: forwards;
}
#keyframes fadeOutOverlay {
to {
opacity: 0;
}
}
.jg {
stroke-dasharray: 395px;
stroke-dashoffset: 395px;
stroke-linecap: square;
animation: drawLetter 4s forwards,
fillLetter 0.3s 4.5s forwards;
}
.pixel {
stroke-dasharray: 49px;
stroke-dashoffset: 49px;
animation:drawPixel 4s forwards,
fillPixel 0.3s 4.5s forwards;
}
.jg,
.pixel {
fill: transparent;
}
#keyframes drawLetter {
to {
stroke-dashoffset: 0;
}
}
#keyframes fillLetter {
to {
fill: var(--type);
}
}
#keyframes drawPixel {
to {
stroke-dashoffset: 0;
}
}
#keyframes fillPixel {
to {
fill: var(--accent);
}
}
<div id="root"></div>
I've been attempting to clean up my HTML file by separating a 2.5k line SVG into it's own file. However, using the <object> tag has been unsuccessful so far. I attempted and succeeded having the the SVG appear with an <img> tag, but it had none of my CSS animations working. Any pointers on how to get this working through an SVG file would be greatly appreciated!
SVG Snippet (2500 LINES)
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 400 400" enable-background="new 0 0 400 400" xml:space="preserve">
<g id="jjperezaguinaga">
<g id="countryObjects">
<path fill="#F15C27" d="M124.467,134.068c-2.028,2.304-3.916,4.723-5.74,7.187c-0.104,0.155-0.359,0.16-0.568,0.012l-14.95-10.734
c-0.208-0.149-0.431-0.462-0.492-0.699c-0.699-2.659-1.231-5.311-1.771-8.085c-0.046-0.243,0.114-0.458,0.359-0.476
c2.819-0.201,5.698-0.233,8.443-0.247c0.239,0,0.59,0.138,0.781,0.308l13.809,12.168
C124.531,133.671,124.588,133.925,124.467,134.068z"/>
<polygon fill="#FFFFFF" points="109.465,128.355 107.582,126.629 109.685,128.071 "/>
<polygon fill="#FFFFFF" points="109.95,127.335 107.582,126.629 109.983,126.959 "/>
<path fill="#FFFFFF" d="M109.84,126.14c-0.774,0.136-1.513,0.311-2.258,0.489l2.092-0.86L109.84,126.14z"/>
<path fill="#FFFFFF" d="M109.129,125.058l-1.547,1.571c0.38-0.634,0.787-1.249,1.219-1.843L109.129,125.058z"/>
<path fill="#FFFFFF" d="M107.994,124.383c-0.166,0.732-0.298,1.487-0.412,2.246c-0.016-0.782-0.027-1.573,0.005-2.34
L107.994,124.383z"/>
...
</svg>
HTML Portion
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF__8">
<title>Overlook</title>
<link type="text/css" href="https://fonts.googleapis.com/css2?family=Roboto:wght#900&display=swap" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<object data="../assets/background.svg" type="image/svg+xml"></object>
CSS Animations
#-webkit-keyframes rotate-right {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
#-webkit-keyframes rotate-left {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(-360deg);
}
}
#-webkit-keyframes hover {
0% {
-webkit-transform: translateY(0%);
}
50% {
-webkit-transform: translateY(5%);
}
100% {
-webkit-transform: translateY(0%);
}
}
#-webkit-keyframes pull {
0% {
-webkit-transform: scaleY(1);
}
40% {
-webkit-transform: scaleY(1.01);
}
60% {
-webkit-transform: scaleY(0.99);
}
80% {
-webkit-transform: scaleY(1.01);
}
100% {
-webkit-transform: scaleY(0.99);
}
80% {
-webkit-transform: scaleY(1.01);
}
100% {
-webkit-transform: scaleY(1);
}
}
#function getSpeed($speed, $type:turtle) {
$secs: 360;
$divider: 1;
#if($type == turtle) {
$divider: 1;
} #else if($type == rabbit) {
$divider: 10;
} #else {
$divider: 60;
}
#if $speed == fastest {
$secs: 60 / $divider;
} #else if $speed == really-fast {
$secs: 120 / $divider;
} #else if $speed == fast {
$secs: 180 / $divider;
} #else if $speed == slow {
$secs: 240 / $divider;
} #else if $speed == really-slow {
$secs: 300 / $divider;
} #else if $speed == slowest {
$secs: 360 / $divider;
}
#return #{$secs}s;
}
#mixin _rotate-animation($direction, $speed, $type) {
-webkit-transform: translate3d(0, 0, 0);
-webkit-animation: rotate-#{$direction} getSpeed($speed, $type) linear 0s infinite;
}
#mixin _hover-animation($duration, $delay) {
-webkit-transform: translate3d(0, 0, 0);
-webkit-animation: hover #{$duration}s linear #{$delay}s infinite;
}
#mixin _pull-animation($duration, $delay, $x: 200px, $y: 200px) {
-webkit-transform: translate3d(0, 0, 0);
-webkit-transform-origin: $x $y;
-webkit-animation: pull #{$duration}s linear #{$delay}s infinite alternate;
}
#mixin rotate($type, $direction: left, $speed: slow, $x: 200px, $y: 200px) {
-webkit-transform: translate3d(0, 0, 0);
-webkit-transform-origin: $x $y;
#include _rotate-animation($direction, $speed, $type);
}
#airplane2, #airplane1 {
#include rotate(turtle, right, fastest);
}
#countryObjects {
#include rotate(turtle, right, slow);
}
#floatingGlobe {
#include rotate(turtle, left, normal);
}
#globe {
$duration: 0;
$delay: 0;
#include _hover-animation($duration, $delay);
}
#windmill {
#include rotate(flash, right, really-fast, 331px, 201px);
}
// Clouds
#for $i from 1 through 3 {
#cloud#{$i} {
#include _hover-animation(3, $i);
}
}
// Inner Circles
#for $i from 1 through 5 {
$direction: left;
$speed: really-fast;
#circle#{$i} {
#if $i % 2 == 1 {
$direction: right;
$speed: really-fast;
} #else {
$direction: left;
$speed: slow;
}
#include rotate(rabbit, $direction, $speed);
}
}
I have a working css animation. I meant it to loop through each child changing the background color with keyframes.
I'm attempting to create a button to pause and run the animation on click. What I have so far works only for the parent. I can only run and pause the parent. I can't make it work for the nested nth-child.
I've tried document.querySelector('.animation1 animation1:nth-child(16n +1) animation1:nth-child(16n + 2))', document.querySelectorAll() but to no avail.
I've also attempted document.getElementsByClassName('animation1').classList.add("animation-run");.
var button = document.getElementById('button-ani');
var test_ani = document.getElementsByClassName('animation1');
button.onclick = function() {
test_ani[0].classList.toggle('playani');
}
/*document.getElementsByClassName('animation1').classList.add("animation-run"); */
.animation1 {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay) paused;
}
/* animation-run
.animation-run {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay);
}
*/
/* Without Paused
.animation1 {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay);
}
*/
.playani {
animation-play-state: running;
}
.animation1:hover {
animation: none;
fill: #666;
}
.animation1:nth-child(16n + 1) {
--animation-delay: 0.2s;
}
.animation1:nth-child(16n + 2) {
--animation-delay: 0.3s;
}
.animation1:nth-child(16n + 3) {
--animation-delay: 0.4s;
}
.animation1:nth-child(16n + 4) {
--animation-delay: 0.5s;
}
.animation1:nth-child(16n + 5) {
--animation-delay: 0.5s;
}
#keyframes ani_keyframes {
0% {
fill: #000;
}
40% {
fill: #FF0;
}
80% {
fill: #330;
}
}
<div id="animation1_wrapper">
<button id="button-ani">Toggle Animation Play State</button>
<svg id="animation1" width="100%" height="100%" viewBox="0 0 418 255" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="ani_graphic">
<path class="animation1" d="M263.46 25.3801C257.63 29.2001 252.88 33.7801 249.33 37.8001H263.46V25.3801Z" fill="#000"></path>
<path class="animation1" d="M301.26 37.8001V18.8701C300.92 18.7801 300.58 18.6801 300.24 18.6001C287.1 15.3201 275.8 18.2901 266.73 23.3901V37.8001H301.26Z" fill="#f1f1f1"></path>
<path class="animation1" d="M329.15 37.8001C324.38 30.2101 316.5 23.6801 304.54 19.8201V37.8001H329.15Z" fill="#f1f1f1"></path>
----
----
</g>
</svg>
</div>
You can simply use a forEach loop and querySelectorAll method to do animation on all the classes when you click play OR when you click it again the animation will stop on all svg elements
querySelectorAll method return a node list of same class found in the DOM tree and using forEach we can iterate through it all and apply toggle class on found element with that class name
Live Working Demo:
var button = document.getElementById('button-ani');
var test_ani = document.querySelectorAll('.animation1');
button.onclick = function() {
test_ani.forEach(function(ani) {
ani.classList.toggle('playani');
})
}
.animation1 {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay) paused;
}
/* animation-run
.animation-run {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay);
}
*/
/* Without Paused
.animation1 {
--animation-delay: 0.1s;
animation: ani_keyframes 1.8s linear infinite var(--animation-delay);
}
*/
.playani {
animation-play-state: running;
}
.animation1:hover {
animation: none;
fill: #666;
}
.animation1:nth-child(16n + 1) {
--animation-delay: 0.2s;
}
.animation1:nth-child(16n + 2) {
--animation-delay: 0.3s;
}
.animation1:nth-child(16n + 3) {
--animation-delay: 0.4s;
}
.animation1:nth-child(16n + 4) {
--animation-delay: 0.5s;
}
.animation1:nth-child(16n + 5) {
--animation-delay: 0.5s;
}
#keyframes ani_keyframes {
0% {
fill: #000;
}
40% {
fill: #FF0;
}
80% {
fill: #330;
}
}
<div id="animation1_wrapper">
<button id="button-ani">Toggle Animation Play State</button>
<svg id="animation1" width="100%" height="100%" viewBox="0 0 418 255" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="ani_graphic">
<path class="animation1" d="M263.46 25.3801C257.63 29.2001 252.88 33.7801 249.33 37.8001H263.46V25.3801Z" fill="#000"></path>
<path class="animation1" d="M301.26 37.8001V18.8701C300.92 18.7801 300.58 18.6801 300.24 18.6001C287.1 15.3201 275.8 18.2901 266.73 23.3901V37.8001H301.26Z" fill="#f1f1f1"></path>
<path class="animation1" d="M329.15 37.8001C324.38 30.2101 316.5 23.6801 304.54 19.8201V37.8001H329.15Z" fill="#f1f1f1"></path>
----
----
</g>
</svg>
</div>
I have an animation on a chart but I want the CSS animation to load once it becomes into the users viewport. Currently it loads on the page load but this means that once the user has scrolled to the section the animation has already occurred.
The HTML & CSS can be seen below:
.chart[data-percent='100'] .outer {
stroke-dashoffset: 0;
-webkit-animation: show100 2s;
animation: show100 2s;
}
.chart[data-percent='96'] .outer {
stroke-dashoffset: 22;
-webkit-animation: show96 2s;
animation: show96 2s;
}
.chart[data-percent='77'] .outer {
stroke-dashoffset: 123;
-webkit-animation: show75 2s;
animation: show75 2s;
}
.chart[data-percent='75'] .outer {
stroke-dashoffset: 133;
-webkit-animation: show75 2s;
animation: show75 2s;
}
.chart[data-percent='52'] .outer {
stroke-dashoffset: 257;
-webkit-animation: show52 2s;
animation: show52 2s;
}
.chart[data-percent='50'] .outer {
stroke-dashoffset: 267;
-webkit-animation: show50 2s;
animation: show50 2s;
}
.chart[data-percent='25'] .outer {
stroke-dashoffset: 401;
-webkit-animation: show25 2s;
animation: show25 2s;
}
#-webkit-keyframes show100 {
from {
stroke-dashoffset: 537;
}
to {
stroke-dashoffset: 0;
}
}
#keyframes show96 {
from {
stroke-dashoffset: 537;
}
to {
stroke-dashoffset: 22;
}
}
#keyframes show75 {
from {
stroke-dashoffset: 537;
}
to {
stroke-dashoffset: 124;
}
}
#-webkit-keyframes show52 {
from {
stroke-dashoffset: 537;
}
to {
stroke-dashoffset: 257;
}
}
#-webkit-keyframes show50 {
from {
stroke-dashoffset: 537;
}
to {
stroke-dashoffset: 267;
}
}
#keyframes show25 {
from {
stroke-dashoffset: 537;
}
to {
stroke-dashoffset: 401;
}
}
<div class="row stat-wheel">
<div class="col-sm-4">
<p class="stat-figure">52%</p>
<figure class="chart" data-percent="52">
<svg width="200" height="200">
<circle class="outer" cx="95" cy="95" r="85" transform="rotate(-90, 95, 95)"/>
</svg>
</figure>
<p class="white center">increase in sales generated through campaigns</p>
</div>
<div class="col-sm-4">
<p class="stat-figure">77%</p>
<figure class="chart" data-percent="77">
<svg width="200" height="200">
<circle class="outer" cx="95" cy="95" r="85" transform="rotate(-90, 95, 95)"/>
</svg>
</figure>
<p class="white center">return on investment in the first 2 months</p>
</div>
<div class="col-sm-4">
<p class="stat-figure">96%</p>
<figure class="chart" data-percent="96">
<svg width="200" height="200">
<circle class="outer" cx="95" cy="95" r="85" transform="rotate(-90, 95, 95)"/>
</svg>
</figure>
<p class="white center">increase in the quality of sales leads generated</p>
</div>
</div>
You can checkout the intersection observer api, it tells you when an element becomes visible in your viewport. You can listen to it and then start your animation.
A very clean way would be using vanilla JS.
Link with explanation
// (c) 2017 Chris Ferdinandi
var isInViewport = function (elem) {
var distance = elem.getBoundingClientRect();
return (
distance.top >= 0 &&
distance.left >= 0 &&
distance.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
distance.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
var findMe = document.querySelector('.row stat-wheel');
window.addEventListener('scroll', function (event) {
if (isInViewport(findMe)) {
console.log('In viewport!');
} else {
console.log('Nope...');
}
}, false);
JavaScript library to animate elements as they scroll into view.
https://scrollrevealjs.org/
I have an image on a React page. When the state is updated to a new image I want to perform the following transition effect:
The original image should zoom in and fade out
The new image should also zoom in and fade in
The effect should look similar to passing through a wall to a new scene.
How am I able to do this in React?
As #pgsandstrom mentioned, React Transition Group is the way to go. Unfortunately, it's not very developer friendly (pretty steep learning curve).
Here's a working example: https://codesandbox.io/s/6lmv669kz
✔ Original image zooms in while fading out
✔ New image zooms in while fading in
TransitionExample.js
import random from "lodash/random";
import React, { Component } from "react";
import { CSSTransition, TransitionGroup } from "react-transition-group";
import uuid from "uuid/v1";
const arr = [
{
id: uuid(),
url: `https://loremflickr.com/600/100?lock=${random(0, 999)}`
},
{
id: uuid(),
url: `https://loremflickr.com/600/100?lock=${random(0, 999)}`
},
{
id: uuid(),
url: `https://loremflickr.com/600/100?lock=${random(0, 999)}`
}
];
export default class TransitionExample extends Component {
state = {
index: 0,
selected: arr[0]
};
nextImage = () =>
this.setState(prevState => {
const newIndex = prevState.index < arr.length - 1 ? prevState.index + 1 : 0;
return {
index: newIndex,
selected: arr[newIndex]
};
});
render = () => (
<div className="app">
<div style={{ marginBottom: 30, height: 100 }}>
<TransitionGroup>
<CSSTransition
key={this.state.selected.id}
timeout={1000}
classNames="messageout"
>
<div style={{ marginTop: 20 }}>
<img className="centered-image" src={this.state.selected.url} />
</div>
</CSSTransition>
</TransitionGroup>
</div>
<div style={{ textAlign: "center" }}>
<button
className="uk-button uk-button-primary"
onClick={this.nextImage}
>
Next Image
</button>
</div>
</div>
);
}
styles.css
.app {
margin: 0 auto;
overflow: hidden;
width: 700px;
height: 800px;
}
.centered-image {
display: block;
margin: 0 auto;
}
/* starting ENTER animation */
.messageout-enter {
position: absolute;
top: 0;
left: calc(13% + 5px);
right: calc(13% + 5px);
opacity: 0.01;
transform: translateY(0%) scale(0.01);
}
/* ending ENTER animation */
.messageout-enter-active {
opacity: 1;
transform: translateY(0%) scale(1);
transition: all 1000ms ease-in-out;
}
/* starting EXIT animation */
.messageout-exit {
opacity: 1;
transform: scale(1.01);
}
/* ending EXIT animation */
.messageout-exit-active {
opacity: 0;
transform: scale(4);
transition: all 1000ms ease-in-out;
}
It sounds like you are looking for React Transition Group. It is the "official" way of solving these issues. Specifically I think this is what you should use. It can be a bit tricky to get a hang of, but it is really nice and powerful once you understand it.
This worked for me (link):
index.js:
import React from "react";
import { render } from "react-dom";
import "./styles.scss";
const src1 =
"https://www.nba.com/dam/assets/121028030322-james-harden-traded-102712-home-t1.jpg";
const src2 = "https://www.nba.com/rockets/sites/rockets/files/wcwebsite.jpg";
var state = {
toggle: true
};
class App extends React.Component {
render() {
const cn1 = "imgFrame " + (state.toggle ? "toggleOut" : "toggleIn");
const cn2 = "imgFrame " + (state.toggle ? "toggleIn" : "toggleOut");
return (
<div>
<img className={cn1} src={src1} alt={"img1"} />
<img className={cn2} src={src2} alt={"img2"} />
<button
onClick={() => {
state.toggle = !state.toggle;
this.forceUpdate();
}}
>
click me to toggle
</button>
<h1>Hello</h1>
</div>
);
}
}
render(<App />, document.getElementById("app"));
style.scss:
html,
body {
background-color: papayawhip;
font-family: sans-serif;
h1 {
color: tomato;
}
}
#keyframes fadeout {
0% {
opacity: 1;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(0.9);
}
}
#keyframes fadein {
0% {
opacity: 0;
transform: scale(1.1);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.toggleOut {
animation: fadeout 500ms;
opacity: 0;
}
.toggleIn {
animation: fadein 500ms;
opacity: 1;
}
.imgFrame {
position: absolute;
top: 10px;
left: 10px;
width: 200px;
height: 200px;
}
button {
position: absolute;
top: 220px;
}
Wrap with a simple <Animate on={value} /> component that triggers an animation when value changes and is not undefined.
function Animate({ children, on }) {
return (on === undefined)
? <div>{children}</div>
: <div className="fade-in" key={on}>{children}</div>
}
import { useEffect, useState } from 'react'
function TestAnimate() {
const [value, setValue] = useState() // undefined
// update value every second
useEffect(() => {
setInterval(() => setValue(new Date().toLocaleString()), 1_000)
}, [])
return (
<Animate on={value}>
Value: {value}
</Animate>
)
}
#keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fade-in {
animation: fadeIn 500ms ease-in-out;
}