Reputation: 3541
I was working with some basic CSS animation for button
.The problem is the :focus
pseudo class even works when we press tab on keyboard. So I want that :focus
should only works when I click on the button i.e only when active.
Here is the code:
button {
background: #c33;
width: 150px;
height: 30px;
border: 0;
color: #fff;
}
button:after {
content: 'RENT ME';
display: block;
}
button:active,
button:focus {
background: green;
}
button:active:after,
button:focus:after {
display: block;
animation: shake 1s linear, revert 2s 1s;
position: relative;
}
@keyframes shake {
from {
content: "O";
font-family: FontAwesome;
transform: rotate(0deg);
}
to {
content: "O";
font-family: FontAwesome;
transform: rotate(360deg);
}
}
@keyframes revert {
0% {
content: 'ADDED TO CART';
left: -60px
}
50% {
content: 'ADDED TO CART';
left: 0px;
}
100% {
content: 'ADDED TO CART';
left: 0px;
}
}
<button></button>
<button></button>
In the above code the button changes to green
on press of tab which I want to avoid.Is there a pure CSS solution to it.
Upvotes: 11
Views: 15301
Reputation: 5183
To avoid the selection of your buttons using the tab key at the start, you can try to avoid the use of the button
element and instead replicate the same behaviour using a div
with a tabindex
attribute.
Use tabindex = "-1"
specifically to avoid the switch via the tabs key.
Refer code :
div {
background: #c33;
width: 150px;
height: 30px;
padding-top: 6px;
border: 0;
color: #fff;
display: inline-block;
align-items: flex-start;
text-align: center;
box-sizing: border-box;
cursor: pointer;
font-size: 12px;
z-index: 10;
outline: 0;
}
div:first-child {
margin-left: 1px;
}
div:after {
content: 'RENT ME';
display: block;
z-index: 10;
}
div:focus {
background: green;
}
div:focus:after {
display: block;
animation: shake 1s linear, revert 2s 1s;
-webkit-animation: shake 1s linear, revert 2s 1s;
position: relative;
}
@keyframes shake {
from {
content: "O";
font-family: FontAwesome;
transform: rotate(0deg);
-webkit-transform: rotate(0deg);
}
to {
content: "O";
font-family: FontAwesome;
transform: rotate(360deg);
-webkit-transform: rotate(360deg);
}
}
@keyframes revert {
0% {
content: 'ADDED TO CART';
left: -60px
}
50% {
content: 'ADDED TO CART';
left: 0px;
}
100% {
content: 'ADDED TO CART';
left: 0px;
}
}
<div tabindex="-1"></div>
<div tabindex="-1"></div>
Upvotes: 0
Reputation: 4527
You can set green background temporary. Is it what you want?
button {
background: #c33;
width: 150px;
height: 30px;
border: 0;
color: #fff;
}
button:after {
content: 'RENT ME';
display: block;
}
button:active,
button:focus {
animation: green-bg 4s step-start;
}
button:active:after,
button:focus:after {
display: block;
animation: shake 1s linear, revert 2s 1s;
position: relative;
}
@keyframes shake {
from {
content: "O";
font-family: FontAwesome;
transform: rotate(0deg);
}
to {
content: "O";
font-family: FontAwesome;
transform: rotate(360deg);
}
}
@keyframes revert {
0% {
content: 'ADDED TO CART';
left: -60px
}
50% {
content: 'ADDED TO CART';
left: 0px;
}
100% {
content: 'ADDED TO CART';
left: 0px;
}
}
@keyframes green-bg {
from {
background: green;
}
to {
background: green;
}
}
<button></button>
<button></button>
Upvotes: 0
Reputation: 655
MY ANSWER IS DIFFERENT FROM OTHERS.
$("button").focus(function() {
$(document).on('keydown', function(event) {
if (event.keyCode == 9) { //tab pressed
event.preventDefault(); // stops its action
}
})
});
$("button").blur(function() {
$("this").unbind();
});
button {
background: #c33;
width: 150px;
height: 30px;
border: 0;
color: #fff;
}
button:after {
content: 'RENT ME';
display: block;
}
button:active,
button:focus {
background: green;
}
button:active:after,
button:focus:after {
display: block;
animation: shake 1s linear, revert 2s 1s;
position: relative;
}
body[data-whatinput="keyboard"] button:focus {
background: red;
}
@keyframes shake {
from {
content: "O";
font-family: FontAwesome;
transform: rotate(0deg);
}
to {
content: "O";
font-family: FontAwesome;
transform: rotate(360deg);
}
}
@keyframes revert {
0% {
content: 'ADDED TO CART';
left: -60px
}
50% {
content: 'ADDED TO CART';
left: 0px;
}
100% {
content: 'ADDED TO CART';
left: 0px;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/what-input/4.1.1/what-input.min.js"></script>
<button tabindex="-1"></button>
<button tabindex="-1"></button>
Upvotes: 0
Reputation: 765
You're not going to get an accessible, or production-worthy solution to this without the use of JavaScript.
If we're to take the purpose of the animation at face value, you're simulating a function that adds an item to a shopping cart. If that's true, you would only want to load the 'added to card' portion of the animation after the item was actually added. By itself, CSS can't know if that's actually true or not, so you'll never get a working solution with CSS alone.
This is unfortunately not the answer you're looking for, as it involves JavaScript, but it is the solution you're looking to achieve.
var myBtn = document.getElementById('rent_me');
myBtn.addEventListener('click', function () {
if ( myBtn.getAttribute('aria-pressed') === 'false') {
myBtn.setAttribute('aria-pressed', 'true');
myBtn.classList.add('loading');
myBtn.querySelector('.init-text').setAttribute('aria-hidden', 'true');
/*
This is to simulate the function of actually
adding this 'item' to the shopping cart.
Wouldn't be used outside of this example
*/
setTimeout( function () {
myBtn.classList.remove('loading');
myBtn.querySelector('.added-text').setAttribute('aria-hidden', 'false')
}, 2000);
}
else {
myBtn.classList.remove('loading');
myBtn.setAttribute('aria-pressed', 'false');
myBtn.querySelector('.init-text').setAttribute('aria-hidden', 'false');
myBtn.querySelector('.added-text').setAttribute('aria-hidden', 'true')
}
});
body {
padding: 20px;
text-align: center;
}
/* setup the button styling */
button {
background: #c33;
border: 2px solid rgba(0,0,0,0);
width: 150px;
height: 40px;
padding: 8px;
position: relative;
color: #fff;
overflow: hidden;
text-align: center;
}
/* the text inside the button is placed within spans that get pushed in/out the bounding of the button with text-indent and overflow hidden */
button span {
position: absolute;
left: 0;
width: 100%;
white-space: nowrap;
transition:
text-indent .2s ease-in-out;
top: 50%;
transform: translateY(-50%);
}
/* start with rent me text in view */
.init-text {
text-indent: 0%;
}
/* added to cart text pushed off to the right */
.added-text {
text-indent: 200%;
}
/* buttons need a focus state so keyboard users know they've 'focused it'
button:focus {
border: 2px solid #000;
}
/* when the button has been activated, JS will set the aria-pressed value to true, changing the background color of the button */
button[aria-pressed="true"] {
background: green;
}
/* if the button has been pressed, get the 'rent me' text out of view */
button[aria-pressed="true"] .init-text {
text-indent: -200%;
}
/* once the button is no longer in the loading phase, bring the 'added to cart' text into view */
button[aria-pressed="true"]:not(.loading) .added-text {
text-indent: 0%;
}
/* when the button is loading, show a spinner */
.loading:before {
transform-origin: center center;
animation: rotate 1s infinite;
position: absolute;
content: "\21BB";
left: 0;
right: 0;
margin: auto;
speak: none;
top: 50%;
transform: translateY(-50%) rotate(0deg);
}
/* animation for the spinner */
@keyframes rotate {
from {
transform: translateY(-50%) rotate(0deg);
}
to {
transform: translateY(-50%) rotate(360deg);
}
}
<button type="button" id="rent_me" aria-pressed="false" aria-live="polite" aria-atomic="true">
<span class="init-text">
Rent Me
</span>
<span class="added-text">
Added to Cart
</span>
</button>
Upvotes: 2
Reputation: 142
use tabIndex="-1"
on button if you don't want the button to be focusable when pressing tab
<button tabIndex="-1"></button>
Upvotes: 7
Reputation: 943214
If a button is active, then it will always be focused at the same time.
So just provide an :active
rule and provide no :focus
rule at all.
Upvotes: 4