Should I use CSS :disabled pseudo-class or [disabled] attribute selector or is it a matter of opinion?
Is the attribute selector the modern CSS3 way and the way to go forward?
- attribute is newer and better
No; actually, attribute selectors have been around since CSS2, and the disabled
attribute itself has existed since HTML 4. As far as I know, the :disabled
pseudo-class was introduced in Selectors 3, which makes the pseudo-class newer.
- there's a technical reason to use one over the other
Yes, to some extent.
With an attribute selector, you're relying on the knowledge that the document you're styling makes use of a disabled
attribute to indicate disabled fields. Theoretically, if you were styling something that wasn't HTML, disabled fields might not be represented using a disabled
attribute, e.g. it might be enabled="false"
or something like that. Even future editions of HTML could introduce new elements that make use of different attributes to represent enabled/disabled state; those elements wouldn't match the [disabled]
attribute selector.
The :disabled
pseudo-class decouples the selector from the document you're working with. The spec simply states that it targets elements that are disabled, and that whether an element is enabled, disabled, or neither, is defined by the document language instead:
What constitutes an enabled state, a disabled state, and a user interface element is language-dependent. In a typical document most elements will be neither
:enabled
nor:disabled
.
In other words, when you use the pseudo-class, the UA automatically figures out which elements to match based on the document you're styling, so you don't have to tell it how. Conversely, the attribute selector would match any element with a disabled
attribute, regardless of whether that element actually supports being enabled or disabled, such as div
. If you're using one of the many modern frameworks that rely on such non-standard behavior, you may be better served by using the attribute selector.
In terms of the DOM, I believe setting the disabled
property on a DOM element also modifies the HTML element's disabled
attribute, which means there's no difference between either selector with DOM manipulation. I'm not sure if this is browser-dependent, but here's a fiddle that demonstrates it in the latest versions of all major browsers:
// The following statement removes the disabled attribute from the first input
document.querySelector('input:first-child').disabled = false;
You're most likely going to be styling HTML, so none of this may make any difference to you, but if browser compatibility isn't an issue I would choose :enabled
and :disabled
over :not([disabled])
and [disabled]
simply because the pseudo-classes carry semantics that the attribute selector does not. I'm a purist like that.
CSS selector for disabled elements
:disabled
pseudo selector will work only for input elements. For div, use div[disabled]
to apply css
Use
div[disabled] {
opacity: 0.4;
filter: alpha(opacity=40); /* For IE8 and earlier */
}
Demo
input:enabled { background: #ffff00;}
input:disabled { background: #dddddd;}div[disabled] { opacity: 0.4; filter: alpha(opacity=40); /* For IE8 and earlier */}
<form action="">First name: <input type="text" value="Mickey"><br>Last name: <input type="text" value="Mouse"><br>Country: <input type="text" value="Disneyland" disabled><br>Password: <input type="password" name="password" value="psw" disabled><br>E-mail: <input type="email" value="john@doe.com" name="usremail"></form><div disabled="disabled">should be transparent</div>
:required or [required] CSS selector
input:required {
border-color: blue;
}
input[required] {
background-color: pink;
}
<input type="text" required>
Is there a difference in CSS selectors `:enabled` vs `not(:disabled)`
Yes, there is a difference — :not(:disabled)
can match elements that are neither :enabled
nor :disabled
. These are elements where enabled/disabled semantics simply don't apply, such as div
, p
, ul
, etc.
The spec confirms this:
What constitutes an enabled state, a disabled state, and a user interface element is language-dependent. In a typical document most elements will be neither
:enabled
nor:disabled
.
Interestingly, the same can't be said for :checked
— there is no corresponding :unchecked
pseudo-class, despite the fact that not all elements have checked/unchecked semantics either. See my answer to this question.
If you're qualifying these pseudo-classes with a type selector (such as input
, select
or textarea
) or a class selector, you probably don't have to worry about this. Still, it makes more sense to use :enabled
than :not(:disabled)
.
Browser support for the majority of level 3 pseudo-classes is indeed identical — there are no known browsers that support either :enabled
or :disabled
only. However, according to MDN it looks like Opera 9.0 and Safari 3.1 don't support :not()
, although they do support :enabled
and :disabled
, and some other features like substring-matching attribute selectors and the general sibling combinator ~
are supported in IE7 with some issues and a little bit better in IE8.
How to use disabled CSS pseudo-class to style element with aria-disabled attributes?
Just apply an attribute selector instead of :disabled
:
[aria-disabled="true"] { /* your declarations */ }
Why is the pseudo-class :read-only not working for a disabled element?
If you test in Firefox, you will see your code working fine so I assume it's a bug or a lack of support for Google Chrome
.pseudo-test input:read-write {
color: blue;
}
.pseudo-test input:read-only {
color: red;
}
<div style="margin-top:10px" class="pseudo-test">
<form action="another-action.php">
<input type="search" value="What do you want to search for?" size="100" disabled>
</form>
</div>
Why is :read-only CSS pseudo-class being applied on this checkbox?
- Because
<input type="checkbox" />
and<input type="radio" />
(and most other elements) are inherently read-only. - Unlike an
<input type="text" />
or<input type="date" />
, when you interact with (i.e. toggle) a checkbox or radio button you are not changing itsvalue
, you are changing itschecked
state. - Yes, I agree it's counter-intuitive.
Consequently...
- You should not apply the
<input readonly
attribute to aradio
orcheckbox
for any purpose.- Because it won't do anything useful.
- You should not define a CSS selector that uses the
:read-only
pseudo-class to select<input>
elements that have an explicit HTML<input readonly
attribute set.- Instead use the has-attribute-selector:
input[readonly]
. - It's probably a good idea just to avoid using the
:read-only
pseudo-class entirely because it also selects pretty-much every HTML element on the page too; a function with little practical utility, imo.
- Instead use the has-attribute-selector:
From the current WHATWG HTML specification (emphasis mine, especially the last point):
https://html.spec.whatwg.org/multipage/semantics-other.html#selector-read-only
The
:read-write
pseudo-class must match any element falling into one of the following categories, which for the purposes of Selectors are thus considered user-alterable: [SELECTORS]
<input>
elements to which the<input readonly
attribute applies, and that are mutable (i.e. that do not have the<input readonly
attribute specified and that are not<input disabled
).<textarea>
elements that do not have a<textarea readonly
attribute, and that are not<textarea disabled
.- elements that are editing hosts or editable and are neither
<input>
elements nor<textarea>
elements.
- [i.e.
contenteditable
]- The
:read-only
pseudo-class must match all other HTML elements.
Now, if you want a "read-only checkbox/radio" then you don't have too many good options, unfortunately; instead you have a mix of terrible options and barely-adequate ones...:
- There is this popular QA, however most of the highest-voted answers have suggestions that I think are bad ideas: such as depending upon a client-script to block user-interaction ...very imperfectly (from people who are ignorant of the fact a radio and checkbox can be manipulated in far, far more many ways than just
onclick
), or using CSS'spointer-events: none;
while completely disregarding the fact that computer keyboards both exist and are regularly used by human computer operators. - The least worst suggestion, I think, is using
<input type="checkbox/radio" disabled />
, as demonstrated with this answer. (The<input type="hidden">
is necessary because disabled (and unchecked) inputs are not submitted, which is another violation of the principle of least astonishment by the then-nascent browser vendors of the late-1990s.
If you want to use the :read-only
pseudo-class on all input
elements except radio and checkboxes then you need to think carefully (and test it too, using variations on document.querySeletorAll("input:read-only")
in your browser's console!)
I recommend that you do not apply any styles using selectors for input
elements without also explicitly specifying the [type=""]
attribute selector - this is because styles with a selector like "input
" (without any attribute-selectors) will be applied to future HTML input elements that we don't know about yet and could be introduced at any point in the near-future, and maybe next week Google Chrome adds a new <input type="human-dna-sample" />
or Microsoft adds <input type="clippy" />
to a particularly retro edition of their Edge browser - so you definitely don't want a :read-only
style applied to those elements until you at least know how it will look and work - and so the browser will use its default/native styling which won't violate your users/visitor's expectations if they happen to come across it on your website at some point.
...so it means you need to write out rules for every known <input type="...">
as repetitive input[type=""]
style rules, and now you might wonder if there were any pseudo-classes for input
elements based on their default native appearance because a lot of them sure do look share similar, if not identical, native appearance and visual-semantics (and shadow DOM structure, if applicable) - for example in desktop Chrome the input types text
, password
, email
, search
, url
, tel
and more are all clearly built around the same native textbox widget, so there surely must be a pseudo-class for different input "kinds", right? Something like input:textbox-kind
for text
, password
, etc and input:checkbox-kind
for checkbox
and radio
- unfortunately such a thing doesn't exist and if introduced tomorrow the W3C's CSS committee probably wouldn't approve it for a few more years at least - so until then we need to explicitly enumerate every input[type=""]
that we know about so that we can accurately anticipate how browsers will render them with our type=""
-specific style rules instead of throwing everything as input {}
and seeing what sticks.
...fortunately the list isn't too long, so I just wrote the rules out just now:
Feel free to copy + paste this; it's hardly even copyrightable. And I want to see how far this spreads across the Internet in my lifetime.
At the bottom is a CSS selector that will select only <input
elements that are from the future by using an exhaustive set of :not([type="..."])
selectors, as well as not matching input
elements with an empty type=""
attribute or missing one entirely.
/* Textbox-kind: */
input[type="text"]:read-only,
input[type="password"]:read-only,
input[type="search"]:read-only,
input[type="tel"]:read-only,
input[type="url"]:read-only,
input[type="email"]:read-only,
input[type="number"]:read-only {
background-color: #ccc;
cursor: 'not-allowed';
}
/* Date/time pickers: */
input[type="date"]:read-only,
input[type="datetime-local"]:read-only,
input[type="time"]:read-only,
input[type="week"]:read-only,
input[type="month"]:read-only {
background-color: #ccc;
cursor: 'not-allowed';
}
/* Button-kind (these are all practically obsolete now btw, as the <button> element is far, far, far superior in every way) */
input[type="button"]:disabled,
input[type="reset"]:disabled,
input[type="submit"]:disabled,
input[type="image"]:disabled {
background-color: #ccc;
border: 1px outset #666;
cursor: 'not-allowed';
color: #666;
text-shadow: 0 1px rgba(255,255,255,0.2);
}
/* Checkbox-kind (Don't use `:read-only` with these): */
input[type="checkbox"]:disabled,
input[type="radio"]:disabled {
/* I'm not setting any properties here because it's impossible to effectively style these elements without resorting to image-replacements using the `:checked` state in selectors for their parent or adjacent `<label>` or ::before/::after` of other proximate elements. */
}
/* Weird-stuff-kind: */
input[type="color"]:read-only,
input[type="file"]:read-only,
input[type="hidden"]:read-only,
input[type="range"]:read-only {
/* Again, due to differences in how different browsers and platforms display (and consequently style) these inputs I don't think it's worth doing anything. */
}
/* If you **really** want to select _future_ <input> elements in-advance... do this: */
input[type]:not([type="text"]):not([type="password"]):not([type="search"]):not([type="tel"]):not([type="url"]):not([type="email"]):not([type="number"]):not([type="date"]):not([type="datetime-local"]):not([type="time"]):not([type="week"]):not([type="month"]):not([type="button"]):not([type="reset"]):not([type="submit"]):not([type="image"]):not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="range"]) {
}
Css pseudo classes input:not(disabled)not:[type= submit ]:focus
Instead of:
input:not(disabled)not:[type="submit"]:focus {}
Use:
input:not([disabled]):not([type="submit"]):focus {}
disabled
is an attribute so it needs the brackets, and you seem to have mixed up/missing colons and parentheses on the :not()
selector.
Demo: http://jsfiddle.net/HSKPx/
One thing to note: I may be wrong, but I don't think disabled
inputs can normally receive focus, so that part may be redundant.
Alternatively, use :enabled
input:enabled:not([type="submit"]):focus { /* styles here */ }
Again, I can't think of a case where disabled input can receive focus, so it seems unnecessary.
Related Topics
Clip-Path Without Clipping Content
Multiple Descendant Children Selector with CSS
Creating an Isoceles Trapezoid Shape
Rails 4: How to Use SASS Mappings
Add a Space (" ") After an Element Using :After
CSS Container Div Not Getting Height
Why Does Enabling Hardware-Acceleration in CSS3 Slow Down Performance
iPhone X/8/8 Plus CSS Media Queries
Styling Twitter Bootstrap Buttons
Absolute Positioning Ignoring Padding of Parent
How to Put Scroll Bar Only for Modal-Body
Hide Up & Down Arrow Buttons (Spinner) in Input Number - Firefox 29
Twitter Bootstrap: Div in Container with 100% Height
Select All 'Tr' Except the First One
How to Add Border Radius on Table Row
Remove Border Radius from Select Tag in Bootstrap 3
Vertically and Horizontally Centering Text in Circle in CSS (Like iPhone Notification Badge)