He achieve this by inserting an element for each sparkle with javascript. I want to do this effect in a web app where I can only use CSS.
My idea is to use several background image on a :after and a :before pseudoelement, to position the stars in front and behind the text and animate each background image (scale rotate).
I managed to scale the background images around their visual center by calculating the correct background-position and background-size, but I have no idea how to also make them rotate in place.
Is it possible with css only ?
Here's what I have so far (I use squares for simplicity sake):
* {
box-sizing: margin-box;
}
:root {
/* Use d='M.5 0A.5.5 90 001 .5.5.5 90 00.5 1 .5.5 90 000 .5.5.5 90 00.5 0' for a star shape */
/* bg images */
--square: url("data:image/svg xml,<svg viewBox='0 0 1 1' xmlns='http://www.w3.org/2000/svg'><path style='vector-effect:non-scaling-stroke' stroke='black' fill='none' stroke-width='1px' opacity='.1' d='M0 0 1 0 1 1 0 1 0 0'/></svg>");
--red: url("data:image/svg xml,<svg viewBox='0 0 1 1' xmlns='http://www.w3.org/2000/svg'><path fill='red' d='m0 0 1 0 0 1L0 1'/></svg>");
--green: url("data:image/svg xml,<svg viewBox='0 0 1 1' xmlns='http://www.w3.org/2000/svg'><path fill='green' d='m0 0 1 0 0 1L0 1'/></svg>");
--blue: url("data:image/svg xml,<svg viewBox='0 0 1 1' xmlns='http://www.w3.org/2000/svg'><path fill='blue' d='m0 0 1 0 0 1L0 1'/></svg>");
/* grid unit */
--unit: calc(100vw/19);
/* set images */
--background-image: var(--square), var(--red), var(--green), var(--blue);
--background-repeat: space, no-repeat, no-repeat, no-repeat;
/* sizes */
--offset-X: 1;
--offset-Y: 1;
--red-scale:3;
--red-size-from:var(--unit);
--red-size-to: calc(var(--unit) * var(--red-scale));
--red-offset:calc((var(--red-scale) - 1)/2);
--offset-X1: 5;
--offset-Y1: 3;
--green-scale:5;
--green-size-from: var(--unit);
--green-size-to: calc(var(--unit) * var(--green-scale));
--green-offset:calc((var(--green-scale) - 1)/2);
--offset-X2: 0;
--offset-Y2: 0;
--blue-scale:19;
--blue-size-from: var(--unit);
--blue-size-to: calc(var(--unit) * var(--blue-scale));
--blue-offset:calc((var(--blue-scale) - 1)/2);
--red-position-from: calc(var(--unit) * calc(var(--offset-X) var(--red-offset))) calc(var(--unit) * (var(--offset-Y) var(--red-offset)));
--red-position-to: calc(var(--unit) * var(--offset-X)) calc(var(--unit) * var(--offset-Y));
--green-position-from: calc(var(--unit) * calc(var(--offset-X1) var(--green-offset))) calc(var(--unit) * (var(--offset-Y1) var(--green-offset)));
--green-position-to: calc(var(--unit) * var(--offset-X1)) calc(var(--unit) * var(--offset-Y1));
--blue-position-from: calc(var(--unit) * calc(var(--offset-X2) var(--blue-offset))) calc(var(--unit) * (var(--offset-Y2) var(--blue-offset)));
--blue-position-to: calc(var(--unit) * var(--offset-X2)) calc(var(--unit) * var(--offset-Y2));
/* result */
--background-size-from: var(--unit), var(--red-size-from), var(--green-size-from), var(--blue-size-from);
--background-size-to: var(--unit), calc(var(--red-size-to)), calc(var(--green-size-to)), calc(var(--blue-size-to));
--background-position-from: 0 0, var(--red-position-from), var(--green-position-from), var(--blue-position-from);
--background-position-to: 0 0, var(--red-position-to), var(--green-position-to), var(--blue-position-to);
}
body {
margin: 0;
aspect-ratio: 1;
background-image: var(--background-image);
background-repeat: var(--background-repeat);
overflow: hidden;
animation: scaling 3s ease infinite alternate;
animation-delay: 0,1s,2s,3s;
}
@keyframes scaling {
from {
background-size: var(--background-size-from);
background-position: var(--background-position-from);
}
to {
background-size: var(--background-size-to);
background-position: var(--background-position-to);
}
}
https://codepen.io/DesignThinkerer/pen/NWaNXOO
CodePudding user response:
Here I'm creating two <symbol>
elements that represent a star each. All animations are done in SVG animations. The two symbols differ a bit in the timing. The <use>
elements refer to the two symbols and I animate the visibility attribute to make the star appear/disappear "randomly". The timing of the visibility is following the timing of the symbols.
In the example I embed the SVG and I have made a Data URL version of the same SVG and using that as a background on the <h1>
.
I fell that this is a fairly simple solution, but maybe you can do something similar using CSS animations.
body {
background: black;
color: white;
}
h1 {
font-family: sans-serif;
display: inline-block;
padding: .2em;
background-size: contain;
background-repeat: no-repeat;
background-image: url('data:image/svg xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTAgMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI CiAgPHN5bWJvbCBpZD0ic3RhcjEiIHZpZXdCb3g9IjAgMCA0IDQiIHdpZHRoPSI1IiBoZWlnaHQ9IjUiPgogICAgPGc CiAgICAgIDxwYXRoIHRyYW5zZm9ybS1vcmlnaW49IjEuNSAxLjUiIGZpbGw9Im9yYW5nZSIKICAgICAgICBkPSJNIDAgMCBDIDEgMSAxIDIgMCAzIEMgMSAyIDIgMiAzIDMgQyAyIDIgMiAxIDMgMCBDIDIgMSAxIDEgMCAwIj4KICAgICAgICA8YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iCiAgICAgICAgICBhdHRyaWJ1dGVUeXBlPSJYTUwiIHR5cGU9InNjYWxlIgogICAgICAgICAgdmFsdWVzPSIwIDA7IDEgMTsgMCAwIgogICAgICAgICAga2V5VGltZXM9IjAgOyAuNCA7IDEiCiAgICAgICAgICBkdXI9IjNzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIvPgogICAgICA8L3BhdGg CiAgICAgIDxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIKICAgICAgICAgIGF0dHJpYnV0ZVR5cGU9IlhNTCIgdHlwZT0icm90YXRlIgogICAgICAgICAgdmFsdWVzPSIwIDEuNSAxLjU7IDkwIDEuNSAxLjUiCiAgICAgICAgICBrZXlUaW1lcz0iMCA7IDEiCiAgICAgICAgICBkdXI9IjFzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIvPgogICAgPC9nPgogIDwvc3ltYm9sPgogIAogIDxzeW1ib2wgaWQ9InN0YXIyIiB2aWV3Qm94PSIwIDAgNCA0IiB3aWR0aD0iNSIgaGVpZ2h0PSI1Ij4KICAgIDxnPgogICAgICA8cGF0aCB0cmFuc2Zvcm09InNjYWxlKDAgMCkiIHRyYW5zZm9ybS1vcmlnaW49IjEuNSAxLjUiIGZpbGw9Im9yYW5nZSIKICAgICAgICBkPSJNIDAgMCBDIDEgMSAxIDIgMCAzIEMgMSAyIDIgMiAzIDMgQyAyIDIgMiAxIDMgMCBDIDIgMSAxIDEgMCAwIj4KICAgICAgICA8YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iCiAgICAgICAgICBhdHRyaWJ1dGVUeXBlPSJYTUwiIHR5cGU9InNjYWxlIgogICAgICAgICAgdmFsdWVzPSIwIDA7IDEgMTsgMCAwIgogICAgICAgICAga2V5VGltZXM9IjAgOyAuNCA7IDEiCiAgICAgICAgICBkdXI9IjNzIiBiZWdpbj0iMS41cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4KICAgICAgPC9wYXRoPgogICAgICA8YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPSJ0cmFuc2Zvcm0iCiAgICAgICAgICBhdHRyaWJ1dGVUeXBlPSJYTUwiIHR5cGU9InJvdGF0ZSIKICAgICAgICAgIHZhbHVlcz0iMCAxLjUgMS41OyA5MCAxLjUgMS41IgogICAgICAgICAga2V5VGltZXM9IjAgOyAxIgogICAgICAgICAgZHVyPSIxcyIgYmVnaW49IjEuNXMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIi8 CiAgICA8L2c CiAgPC9zeW1ib2w CgogIDx1c2UgaHJlZj0iI3N0YXIxIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyIDEpIj4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InZpc2liaWxpdHkiIHZhbHVlcz0idmlzaWJsZTtoaWRkZW47aGlkZGVuO3Zpc2libGU7aGlkZGVuO2hpZGRlbiIgIGtleVRpbWVzPSIwOy4yOy40Oy42Oy44OzEiIGR1cj0iMTVzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgLz4KICA8L3VzZT4KICAKICA8dXNlIGhyZWY9IiNzdGFyMSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoOCAyKSI CiAgICA8YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ2aXNpYmlsaXR5IiB2YWx1ZXM9ImhpZGRlbjt2aXNpYmxlO2hpZGRlbjt2aXNpYmxlO2hpZGRlbjtoaWRkZW4iICBrZXlUaW1lcz0iMDsuMjsuNDsuNjsuODsxIiBkdXI9IjE1cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIC8 CiAgPC91c2U CiAgCiAgPHVzZSBocmVmPSIjc3RhcjEiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI2IDIpIj4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InZpc2liaWxpdHkiIHZhbHVlcz0iaGlkZGVuO2hpZGRlbjtoaWRkZW47dmlzaWJsZTt2aXNpYmxlO2hpZGRlbiIgIGtleVRpbWVzPSIwOy4yOy40Oy42Oy44OzEiIGR1cj0iMTVzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgLz4KICA8L3VzZT4KICAKICA8dXNlIGhyZWY9IiNzdGFyMiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAgNikiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0idmlzaWJpbGl0eSIgdmFsdWVzPSJ2aXNpYmxlO2hpZGRlbjtoaWRkZW47dmlzaWJsZTtoaWRkZW47aGlkZGVuIiAga2V5VGltZXM9IjA7LjI7LjQ7LjY7Ljg7MSIgZHVyPSIxNXMiIGJlZ2luPSIxLjVzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgLz4KICA8L3VzZT4KICAKICA8dXNlIGhyZWY9IiNzdGFyMiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjAgNSkiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0idmlzaWJpbGl0eSIgdmFsdWVzPSJ2aXNpYmxlO2hpZGRlbjt2aXNpYmxlO2hpZGRlbjt2aXNpYmxlO2hpZGRlbiIgIGtleVRpbWVzPSIwOy4yOy40Oy42Oy44OzEiIGR1cj0iMTVzIiBiZWdpbj0iMS41cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIC8 CiAgPC91c2U CiAgCiAgPHVzZSBocmVmPSIjc3RhcjIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDM0IDYpIj4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9InZpc2liaWxpdHkiIHZhbHVlcz0iaGlkZGVuO3Zpc2libGU7dmlzaWJsZTtoaWRkZW47dmlzaWJsZTtoaWRkZW4iICBrZXlUaW1lcz0iMDsuMjsuNDsuNjsuODsxIiBkdXI9IjE1cyIgYmVnaW49IjEuNXMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiAvPgogIDwvdXNlPgo8L3N2Zz4=')
}
svg {
border: solid thin gray;
}
<h1>Sparkly text.</h1>
<svg viewBox="0 0 50 10" xmlns="http://www.w3.org/2000/svg">
<symbol id="star1" viewBox="0 0 4 4" width="5" height="5">
<g>
<path transform-origin="1.5 1.5" fill="orange"
d="M 0 0 C 1 1 1 2 0 3 C 1 2 2 2 3 3 C 2 2 2 1 3 0 C 2 1 1 1 0 0">
<animateTransform attributeName="transform"
attributeType="XML" type="scale"
values="0 0; 1 1; 0 0"
keyTimes="0 ; .4 ; 1"
dur="3s" repeatCount="indefinite"/>
</path>
<animateTransform attributeName="transform"
attributeType="XML" type="rotate"
values="0 1.5 1.5; 90 1.5 1.5"
keyTimes="0 ; 1"
dur="1s" repeatCount="indefinite"/>
</g>
</symbol>
<symbol id="star2" viewBox="0 0 4 4" width="5" height="5">
<g>
<path transform="scale(0 0)" transform-origin="1.5 1.5" fill="orange"
d="M 0 0 C 1 1 1 2 0 3 C 1 2 2 2 3 3 C 2 2 2 1 3 0 C 2 1 1 1 0 0">
<animateTransform attributeName="transform"
attributeType="XML" type="scale"
values="0 0; 1 1; 0 0"
keyTimes="0 ; .4 ; 1"
dur="3s" begin="1.5s" repeatCount="indefinite"/>
</path>
<animateTransform attributeName="transform"
attributeType="XML" type="rotate"
values="0 1.5 1.5; 90 1.5 1.5"
keyTimes="0 ; 1"
dur="1s" begin="1.5s" repeatCount="indefinite"/>
</g>
</symbol>
<use href="#star1" transform="translate(2 1)">
<animate attributeName="visibility" values="visible;hidden;hidden;visible;hidden;hidden" keyTimes="0;.2;.4;.6;.8;1" dur="15s" repeatCount="indefinite" />
</use>
<use href="#star1" transform="translate(8 2)">
<animate attributeName="visibility" values="hidden;visible;hidden;visible;hidden;hidden" keyTimes="0;.2;.4;.6;.8;1" dur="15s" repeatCount="indefinite" />
</use>
<use href="#star1" transform="translate(26 2)">
<animate attributeName="visibility" values="hidden;hidden;hidden;visible;visible;hidden" keyTimes="0;.2;.4;.6;.8;1" dur="15s" repeatCount="indefinite" />
</use>
<use href="#star2" transform="translate(10 6)">
<animate attributeName="visibility" values="visible;hidden;hidden;visible;hidden;hidden" keyTimes="0;.2;.4;.6;.8;1" dur="15s" begin="1.5s" repeatCount="indefinite" />
</use>
<use href="#star2" transform="translate(20 5)">
<animate attributeName="visibility" values="visible;hidden;visible;hidden;visible;hidden" keyTimes="0;.2;.4;.6;.8;1" dur="15s" begin="1.5s" repeatCount="indefinite" />
</use>
<use href="#star2" transform="translate(34 6)">
<animate attributeName="visibility" values="hidden;visible;visible;hidden;visible;hidden" keyTimes="0;.2;.4;.6;.8;1" dur="15s" begin="1.5s" repeatCount="indefinite" />
</use>
</svg>