I have a button to which I applied a costant, rotating animation.
@keyframes rotateinf {
from { transform: rotate( 0deg); }
to { transform: rotate(360deg); }
}
The problem is: the child text gets the animation applied too.
I managed to make a cheap workaround for this problem, I created a element and set the position to absolute, placing it directly on top of the button with top and right attributes.
The imptxt
class just establishes the font.
<span class="imptxt" style="position: absolute;z-index: 10; color: black; top:40%; right:44%; pointer-events: none;"
>
All about
</span>
<span class="imptxt" style="position: absolute;z-index: 10; color: black; top:48%; right:48%; pointer-events: none;"
>
me
</span>
<button id="trns" class="buttonrot" onmousedown="redirect()"></button>
The buttonrot class is the following:
padding: 200px ;
border-radius: 50px;
z-index: 9;
animation:fadeintop 1s ease-in-out, rotateinf 10s linear infinite 1s;
position: relative;
display: inline-block;
cursor: pointer;
overflow: hidden;
transform-origin: center;
This is the result (.gif):
Is there an actual and better way to make the text stay still and apply the rotating animation on the button?
Code snippet:
.buttonrot {
padding: 200px;
border-radius: 50px;
z-index: 9;
animation: fadeintop 1s ease-in-out, rotateinf 10s linear infinite 1s;
position: relative;
display: inline-block;
cursor: pointer;
overflow: hidden;
transform-origin: center;
}
@keyframes rotateinf {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
<span class="imptxt" style=" position: absolute;z-index: 10; color: black; top:40%; right:44%; pointer-events: none;">All about</span>
<span class="imptxt" style="position: absolute;z-index: 10; color: black; top:48%; right:48%; pointer-events: none;">me</span>
<button id="trns" class="buttonrot" onmousedown="redirect()"></button>
0
Put the text in a span
inside the button and the reverse the animation on the span
.buttonrot {
padding: 50px;
border-radius: 10px;
animation: rotateinf 10s linear infinite;
position: relative;
display: inline-block;
cursor: pointer;
overflow: hidden;
}
.buttonrot span {
display: inline-block;
animation: rotateinf 10s linear reverse infinite;
}
@keyframes rotateinf {
100% {
transform: rotate(360deg);
}
}
<button id="trns" class="buttonrot" onmousedown="redirect()"><span>All About Me</span></button>
2
I highly recommend to keep form elements’ markup as “unopinionated” as possible:
Referring to your first approach:
<span class="imptxt" style="position: absolute;z-index: 10; color: black; top:40%; right:44%; pointer-events: none;"
>
All about
</span>
<span class="imptxt" style="position: absolute;z-index: 10; color: black; top:48%; right:48%; pointer-events: none;"
>
me
</span>
<button id="trns" class="buttonrot" onmousedown="redirect()"></button>
When separating the button text “All about me” by adding these as separate <span>
elements you run into accessibility issues as visually-impaired users using a screen-reader won’t get a descriptive text for the <button>
element itself.
Another approach could be to keep the <button>
as it is and prepend an absolutely positioned (and eventuelly animated/rotated) pseudo-element via CSS :before
like so:
*{
box-sizing:border-box;
}
.buttonrot{
font-size:2em;
line-height:1.2em;
color:inherit;
aspect-ratio: 1;
position:relative;
width: 200px;
/* force line-break by horizontal padding */
padding: 0 1em;
/* center content horizontally and vertically */
display:inline-flex;
justify-content: center;
align-items:center;
/* reset default button styles*/
appearance:none;
background:none;
border:none;
cursor: pointer;
/* just for illustration */
outline: 1px dotted #000;
}
/* rotating background */
.buttonrot:before{
content:'';
position:absolute;
inset:0;
background:#ddd;
border: 2px solid #999;
z-index:-1;
border-radius:10px;
transform-origin: center;
animation: rotateinf 5s linear infinite;
}
@keyframes rotateinf {
100% {
transform: rotate(360deg);
}
}
<p style="text-align:center;">
<button class="buttonrot">All about me</button>
</p>
Basically we’re not rotating the button itself but instead rotate a background pseudo-element. This way we don’t need a counter-rotation to make the text-content appear unrotated – it is in fact not rotated at any time.
The problem is: the child text gets the animation applied too.
In fact we’re changing the previous “parent-child” relation to a sibling-relation (OK – the :before
pseudo-element would actually be a “pseudo-older-sibling” and the button text is a text node … I think you get the gist =)
Default button styles
Especially iOS safari is infamous for introducing opinionated default styles for buttons and other form elements. So a slight style-reset like appearance:none
can help to get a more consistent cross-browser styling.
Other benefits:
- we can reduce the amount of animations that may eventually lead to performance issues on less performant devices.
- we can easily re-style the buttons to a more minimalistic/default design without the need to change the HTML structure
- the button itself could be animated separately (e.g by a “fly-in” transition) without complicting the rotation animation.
* {
box-sizing: border-box;
}
p,
h3 {
text-align: center;
}
body {
font-family: sans-serif;
}
.buttonrot {
font-family: inherit;
font-size: 2em;
line-height: 1.2em;
color: inherit;
aspect-ratio: 1;
position: relative;
width: 200px;
/* force line-break by horizontal padding */
padding: 0 1em;
/* center content horizontally and vertically */
display: inline-flex;
justify-content: center;
align-items: center;
/* reset default button styles*/
appearance: none;
background: none;
border: none;
cursor: pointer;
}
/* rotating background */
.buttonrot:before {
content: '';
position: absolute;
inset: 0;
background: #ddd;
border: 2px solid #999;
z-index: -1;
border-radius: 10px;
transform-origin: center;
animation: rotateinf 5s linear infinite;
}
@keyframes rotateinf {
100% {
transform: rotate(360deg);
}
}
<p>
<button class="buttonrot">All about me</button>
</p>
<p>
<a class="buttonrot">All about me</a>
</p>
<h3>Regular button</h3>
<p style="text-align:center;">
<button>All about me</button>
</p>
You can even use the ::after property to achieve what you want, without any additional element.
.buttonrot {
padding: 50px;
border-radius: 10px;
animation: rotateinf 10s linear infinite;
position: relative;
display: inline-block;
cursor: pointer;
overflow: hidden;
}
.buttonrot::after {
content: attr(data-text);
display: inline-block;
animation: rotateinf 10s linear reverse infinite;
}
@keyframes rotateinf {
100% {
transform: rotate(360deg);
}
}
<button id="trns" class="buttonrot" onmousedown="redirect()" data-text="About Me"></button>