I am working to redo this Codepen in React Typescript. I found it in the blogpost here Simple way - creating React App and adding into css file it works perfect. No I tried the way with styled components and it seems I am missing something as it does not work yet?
App.tsx
import React from "react";
import "./App.css";
import styled from "styled-components";
/* Animate when Houdini is available */
const Houdini = styled.div`
width: 400px;
height: 300px;
border-radius: 10px;
padding: 2rem;
margin: auto;
display: grid;
place-content: center;
text-align: center;
font-size: 1.5em;
--border-size: 0.3rem;
border: var(--border-size) solid transparent;
/* Paint an image in the border */
border-image: conic-gradient(
from var(--angle),
#d53e33 0deg 90deg,
#fbb300 90deg 180deg,
#377af5 180deg 270deg,
#399953 270deg 360deg
)
1 stretch;
background: rgb(255 255 255 / var(--opacity));
@supports (background: paint(houdini)) {
@property --opacity {
syntax: "<number>";
initial-value: 0.5;
inherits: false;
}
@property --angle {
syntax: "<angle>";
initial-value: 0deg;
inherits: false;
}
@keyframes opacityChange {
to {
--opacity: 1;
}
}
@keyframes rotate {
to {
--angle: 360deg;
}
}
.rainbow {
animation: rotate 4s linear infinite, opacityChange 3s infinite alternate;
}
/* Hide the warning */
.warning {
display: none;
}
}
`;
function App() {
return (
<>
<Houdini>
<p>
This demo uses a real border with <code>border-image</code>, a
background, and finally Houdini to animate.
</p>
</Houdini>
<div>
<p>
⚠️ Your browser does not support{" "}
<a href="https://web.dev/css-individual-transform-properties/">
@property
</a>{" "}
so the animation won’t work
<br />
Please use Chrome.
</p>
</div>
</>
);
}
export default App;
And a slight variation the working Codepen And the change in my App.tsx the rest is the same like above - same issue, I used styled components and the effect does not show.
const Houdini = styled.div`
.
.
.
--border-size: 0.3rem;
border: var(--border-size) dotted transparent;
background-image: linear-gradient(
to right,
rgb(255 255 255 / var(--opacity)),
rgb(255 255 255 / var(--opacity))
),
conic-gradient(
from var(--angle),
#d53e33 0deg 90deg,
#fbb300 90deg 180deg,
#377af5 180deg 270deg,
#399953 270deg 360deg
);
background-origin: border-box;
background-clip: padding-box, border-box;
.
.
.
`;
The culprit is the nested CSS rule that launches the animation:
.rainbow {
animation: rotate 4s linear infinite, opacityChange 3s infinite alternate;
}
...which, in the CodePen sample, targets the element with the border:
<div class="rainbow">
<p>This demo uses a real border with <code>border-image</code>,
a background, and finally Houdini to animate.</p>
</div>
But once converted to styled-components, the <div>
with the "rainbow" class name was replaced by the <Houdini>
styled React component. Hence its class name is no longer "rainbow", but generated by styled-components.
<Houdini> // styled-components replaces it by something like "<div class="sc-bczRLJ kCseJt">"
<p>
This demo uses a real border with <code>border-image</code>, a
background, and finally Houdini to animate.
</p>
</Houdini>
In order to achieve the same effect (i.e. preparation then a nested rule to launch the animation, applied on the same class name), we can simply use the &
(ampersand) identifier, that styled-components replaces by the generated class name (SASS/SCSS technique):
https://styled-components.com/docs/basics#pseudoelements-pseudoselectors-and-nesting
&
a single ampersand refers to all instances of the component; it is used for applying broad overrides
& /*.rainbow*/ {
animation: rotate 4s linear infinite, opacityChange 3s infinite alternate;
}
...and now the animation works!
Note: do not forget to also define your initial CSS variables (e.g. in the global CSS file):
:root {
--angle: 45deg;
--opacity: 0.5;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
Demo on CodeSandbox: https://codesandbox.io/s/winter-dream-ej7yec?file=/src/App.tsx:1069-1176