Differentiate between :focus via tab-key and :focus via click in CSS - css

Although I am quite certain that the answer to my question will be "Can't be done" I'd like to be sure and ask you guys here.
I have a rather typical scenario in which I want to enable tabbing through my website (i.e. using tab key on keyboard). The item the user has just tabbed upon should be marked visually via CSS. So far, so good. This, obviously, demands the focus-pseudo class:
a {
color: #000;
&:hover {
color: lighten(#000, 10%); // discreet change
}
&:focus {
background-color: green; // extreme change
}
}
But I want to apply this style solely when the user tabs through the page. When the user hovers or clicks an element the style should be something different.
Example: A user hovers or clicks an anchor. Then the visual aid can be discreet because the user already knows which element he has interacted upon. But when he tabs through the page he can not be so sure and thus the styling should be more drastic.
The problem I am having is: An element gets the focus-styles applied on on both tabbing the page and clicking on it.
Is there a CSS-only way to apply styles solely when an element got focused via tabbing?
Again, I am pretty sure that this is not possible, but just to be sure I have asked the question.

There's a new CSS selector :focus-visible that is intended to solve this scenario by targeting only the elements that were focused via keyboard input.
This is only supported natively in Firefox today, however there is a polyfill that makes this possible in all browsers through a .focus-visible class name.

The :focus pseudo-class does not discriminate based on how the element entered focus in the first place. So indeed, this is not possible with just CSS. At the very least you'd need to annotate the element on focus via an event handler.
The :hover and :active pseudo-classes won't be of any help here since the former only applies when the mouse pointer is on the element and the latter only applies when the mouse button is down, i.e. neither state persists the way :focus does, since an element remains in focus even after the mouse pointer has left the element, making it indistinguishable from an element that received focus via tabbing.

Just so to list this as an alternative answer (which I also chose, tbh):
One can also work with javascript to disable the mousedown-event. This event is not really that useful, the click-event still works and it prevents the clicked element from getting the focus-state. This, in turn, makes using the :focus property in CSS useful again as it now only triggers when the user navigates that element via tab key.

I didn't have any luck with pure CSS so I wrote a simple fiddle:
var allowTabFocus = false;
$(window).on('keydown', function(e) {
console.log(e);
$('*').removeClass('tab-focus');
if(e.keyCode === 9) {
allowTabFocus = true;
}
});
$('*').on('focus', function() {
if(allowTabFocus) {
$(this).addClass('tab-focus');
}
});
$(window).on('mousedown', function() {
$('*').removeClass('tab-focus');
allowTabFocus = false;
})

Related

Google Chrome showing black border on focus state for button user agent styles

Recently i was working on a web design project, and noticed something odd, after the last Google Chrome update. The default border style(user agent style) for button is changed, and which is looking visually annoying to me.
Is there any method to modify/restore the default browser styles, i.e., user agent styles permanently?
here are some images of the problem:
i have also checked other websites and even google
also checked the dev tool, found this border styles applied on the focus state of the button
This is because the new chrome update
https://developers.google.com/web/updates/2020/05/nic83#forms
you can override black outline in most cases by
*,*:focus,*:hover{
outline:none;
}
and you can see this article
https://web.dev/style-focus/#use-:focus-visible-to-selectively-show-a-focus-indicator
if you want to remove outline just for mouse user.
You could try disabling this flag: chrome://flags/#form-controls-refresh 
Apparently the 83+ version of chrome changed how forms are rendered / handled:
https://blog.chromium.org/2020/03/updates-to-form-controls-and-focus.html
Here is a relevent Google Support page which links to the blog post above:
https://support.google.com/chrome/thread/48974735?hl=en
The issue isn't Chromium's new contrasting focus ring, it's the default behavior across browsers that clicking triggers the focus ring.
The focus ring appears on click when the <button> appearance is altered or receives tabindex attribute.
Accessibility is a must and the new contrasting black and white focus ring is a great step forward. However there are developers (including me) that don't want the focus ring to be present when using the mouse.
Solutions
:focus-visible css pseudo selector. Supported on all modern browsers MDN Browser Compatibility
/*
This will hide the focus indicator if the element receives focus via the mouse,
but it will still show up on keyboard focus.
*/
button:focus:not(:focus-visible) {
outline: none;
}
focus-visible polyfill
/*
This will hide the focus indicator if the element receives focus via the mouse,
but it will still show up on keyboard focus.
*/
.js-focus-visible :focus:not(.focus-visible) {
outline: none;
}
if you're using a framework that overrides classes, use the focus visible attributes.
[data-js-focus-visible] :focus:not([data-focus-visible-added]) {
outline: none;
}
Keep in mind that for mobile users, if there's an element that triggers the soft keyboard to pop up, such as <input type="text">, it should have visual indication that it is focused.
There are 2 way to handle it.
configuration in chrome which few has suggested.
Programmatically approach outline: 0px transparent !important; in style Or outline: none !important; Both have worked for me.
Since we can't force user to do configuration, I would suggest for second Option but it is long process If you have any shorter way tell us.
This solved it for me:
chrome://flags/#form-controls-refresh
And disable this: screenshot
settings in chrome > Appearance > Show a quick highlight on the focused object.
Disable this option.
Go to chrome desktop browser
settings->Advanced->Accessibility->(Turn off)Show a quick highlight on the focused object
to avoid the shadow boxes when u click on your browser

Hover effect if button is not disabled?

I have the following CSS rule:
button.medium.fade-btn:hover:not([disabled]) {
color:red;
}
And HTML code:
<button class="medium fade-btn" disabled></button>
I need that hover effect works only when button is not disabled.
You haven't structured your selector properly
button.medium.fade-btn:hover:not([disabled])
In theory selects nothing, but is searching the children of button (which there are none) due to you putting it after the hover.
button.medium.fade-btn:not([disabled]):hover
Is the correct way.
Hover is the event so you want that happening on the not disabled button so it comes after everything else. Select the element and then use the hover as the last part. It may be easier to work with disabled: true/false as well.
Edit: This is either a browser compatibility problem, or your browser isn't liking just using disabled in the type selector. You should try using disabled=true in your selector and checking your browser version against the versions that :not() is supported in.

Is it more performant to defer CSS to :hover if possible?

Consider the following:
.element {
cursor: pointer;
}
.element:hover {
cursor: pointer;
}
To me, these two CSS snippets are identical. The cursor is only seen when hovering the element. Either method of decorating the cursor works equally well.
I'm curious how this works under the hood. Is there a preference here for using one or the other? If so, why?
Let's do some analysis here. The only difference is the hover pseudo-element, which declaratively indicates to change the rendering in response to user actions.
The cursor property description in the CSS3 spec contains the following:
This property specifies the type of cursor to be displayed for the
pointing device when over the element's border, padding, and content.
This can be interpreted as modifying the cursor as a response to a mouseover event.
On the other end the :hover pseudo selector description in the CSS3 Spec contains the following:
A visual user agent could apply this pseudo-class when the cursor (mouse pointer) hovers over a box generated by the element.
This applies a whole set of properties to the element in question as a response to a mouseover event, which could mean repainting some of the portions of the screen if you had some other properties in there, but since you are only setting the mouse cursor a repaint should not happen, so using hover with cursor can be considered as syntactic over-complication for your specific example, since they do exactly the same.
For your concrete example there should not be any significant performance difference since in both cases a mouse over event is raised, and an event handler in native code applies the new cursor. A repaint does not happen.
As I see, you only need the :hover if you want more actions or different pointers than the default when hovering the item, like these:
.element.crosshair {
cursor: crosshair;
}
.element.help {
cursor: help;
}
.element.wait {
cursor: wait;
}
The difference as per performance is too minor to even matter.
The cursor only could be seen once over anyway.
I think it's best to apply the cursor style to the element.
Check this fiddle (and probably best to do so using Chrome).
Each button creates 500,000 paragraphs with no spacing between them:
JS:
function paragraphs(className) {
var s= '';
for(var i = 0 ; i < 500000 ; i++) {
s+= '<p class="'+className+'"></p>';
}
document.querySelector('div').innerHTML= s;
}
CSS:
p {
margin: 0;
}
The first button applies the cursor on the element, the second applies it on the hover pseudo class.
The cursor should not change when moving between paragraphs. However, it does when the style is applied on the pseudo class.

How to set multiple conditions on css3

I'm trying to write script on css that display a div on click and hide another div at same time.
CSS:
.box{
display:none
}
.box:target{
display:block;
}
You can't, because CSS doesn't listen for client-side clicks. The closest you'll get is :active, which registers when the mouse button is held down.
You can, however, do this with the Checkbox Hack: http://tympanus.net/codrops/2012/12/17/css-click-events/
1 Wrap an element in a checkbox
2 Use CSS like this: input[type=checkbox]:checked ~ #IDOfElementWrappedInCheckbox
And, also on the link,
The :target Way:
'There is another way, well known to “fake” a click event with CSS, using the :target pseudo-class. This pseudo-class is quite similar to the :hover one in the way that it matches only a specific scenario.
The special event for the :target pseudo-class depends on what we call a “fragment identifier”. To put it simple, this pseudo-class refers to a hashtag you can see sometimes at the end of the URL. So it matches when the hashtag and the ID of an element are the same.
The HTML
Click me!
<p id="id" class="to-be-changed">I'm going to be red! It's gonna be legen... Wait for it...</p>
The CSS
.to-be-changed {
color: black;
}
.to-be-changed:target {
color: red;
}
Basically, when clicking on the link (href="#id"), the URL changes and you go to the anchor #id in the page. In this very moment, the element having this id can be targeted with the :target pseudo-class.'
'and the :focus way (also on the link):
THE :FOCUS WAY
Let’s continue with another way using a pseudo-class; the :focus one this time. It’s pretty much the same idea, except, it doesn’t expect a URL change. It relies on the user’s focus on a particular element.
When you’re on a web page, you can press the tab key to navigate through various elements on the page. It’s particularly useful when filling forms, to go from one field to another without having to use the mouse. It’s also used by blind or visually impaired people to navigate through a site.
What’s important to note is that some elements can be focused, like links, inputs and such, and some other can’t, like paragraphs, divisions, and plenty others. Actually they can, but you’ll need to add the tabindex attribute with a numeric value.
How it works
The HTML
<span tabindex="0">Click me!</span>
<p class="to-be-changed">I'm going to be red! It's gonna be legen... Wait for it...</p>
The CSS
span:focus ~ .to-be-changed {
color: red;
}
So, when you click on the span or reach it with the tab key, it becomes focused and matches the :focus pseudo-class. The adjacent sibling selector does the rest. Pretty easy, right? If you don’t want to mess with the tabindex for any reason, you can simply use a link with a # href. It will work like a charm as well.'
The last thing on the link,
'
The Transition Hack
This is probably the most wicked way to handle a click event in CSS. Seriously guys, this is madness. This technique comes from Joel Besada and has always been one of my favorite CSS tricks.
The idea is to store a CSS style in a CSS transition. Yeah, you read it right, a CSS transition. Actually, the idea is pretty simple. It relies on applying a pseudo-infinite delay to a change in order to prevent it to get back to the default value. It may sound complicated but it’s fairly easy, trust me. Please have a look at the code.
How it works
The HTML
<span>Click me!</span>
<p class="to-be-changed">I'm going to be red! It's gonna be legen... Wait for it...</p>
The CSS
.to-be-changed {
transition: all 0s 9999999s;
}
span:active ~ .to-be-changed {
transition: all 0s;
color: red;
}
The idea behind the first declaration is to delay any change to approximately 116 days to make sure the changes will stay once they’ve been set. It is not infinite, but kind of, right?
But we don’t want to apply the changes 116 days after clicking, we want it to be set immediately! So the idea is to override the delay during the click (:active pseudo-class) to apply the changes. Then when the click will be released, the old transition property will kick back in, setting back the delay to 9999999s, preventing the changes to going back to the default state.'
i turn my comment into a short answer.
For youger browser you might do it in CSS.
.
shy , :focus ~ .show {
display:none;
}
:focus ~ .shy {
display:block;
}
:focus { /* toggle hide/show) just loosing focus on click */
pointer-events:none;
}
<p tabindex="0">click to hide/show (toggle) next content</p>
<div class="show"> shown if no click</div>
<div class="shy">shown if clicked</div>
http://codepen.io/gc-nomade/pen/oxybl

How to style button inputs to be identical in Chrome and Firefox?

Take a look at this JSFiddle example in Chrome and FireFox.
In Chrome, the button should be a tad smaller than in FireFox. I have added the solution CSS from How to reset default button style in Firefox 4 + (which made the button a little smaller) but the button is still bigger in FireFox. The difference isn't very visible in this example, but have a look at how it affects my design.
Chrome:
FireFox:
As you can see the button is thicker in FireFox and is affecting the layout. Is there any way of avoiding this short of using styled divs in place of buttons?
Also, I'm using Meyer's CSS reset stylesheet
Firefox adds a special padding to inputs and button elements. This takes care of it:
button::-moz-focus-inner,
input[type="button"]::-moz-focus-inner,
input[type="submit"]::-moz-focus-inner,
input[type="reset"]::-moz-focus-inner {
padding: 0 !important;
border: 0 none !important;
}
I have concluded that the only way of ensuring that button/submit inputs remain identical across browsers is to recreate them using divs. Creating button inputs is easy since you can attach click events onto divs the same way as on buttons. Creating submit inputs is barely any harder. I solved it using jQuery by declaring a class, for instance 'submit', and adding the submit button functionality to all elements that have that class on load. Here's an exampe:
// On page load:
$('.submit').on('click', function(e) {
$(this).closest('form').submit();
});
Divs with the submit class that are not in a form will do nothing when clicked.
If you add tabindex="n" (where n is a number) to the element, it can also be focused using tab, just like a normal button. You can also style it to show that it's focused by using the :focus css pseudo-class. Then you could use space or enter to click the button with this event handler:
$('.submit').on('keypress', function(e) {
if (e.keyCode == 13 || e.keyCode == 32)
$(this).closest('form').submit();
});
(I wrote that last snippet in a hurry and haven't actually tested it. If you find an error in it or test it successfully please edit this answer accordingly.)
Have you by any chance set a line-height on the buttons on your page? You haven't on the fiddle, but line-height's other than normal, aren't accepted on firefox, and some other browser I believe - maybe IE, I'm not sure.
Have you tried a CSS reset? I dont have FF on this computer or else I would check if this works.
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.5.1/build/cssreset/cssreset-min.css">

Resources