Using multiple vendor-specific CSS selectors at once - css

I'm styling placeholder text, and need to use several vendor-prefixed selectors so that it works in different browsers. When I put each of them as a separate code block, it works. However, if I use a comma-separated list of selectors instead of repeating the same CSS for each of them, it won't work. Can anyone explain?
This works:
input[type=text]::-webkit-input-placeholder {
color: green;
}
input[type=text]::-moz-placeholder {
color: green;
}
input[type=text]:-ms-input-placeholder {
color: green;
}
input[type=text]:-moz-placeholder {
color: green;
}
<input type="text" placeholder="Placeholder Text" />
But this doesn't:
input[type=text]::-webkit-input-placeholder,
input[type=text]::-moz-placeholder,
input[type=text]:-ms-input-placeholder,
input[type=text]:-moz-placeholder {
color: green;
}
<input type="text" placeholder="Placeholder Text" />
Why?

Unfortunately, you can't.
When a selector that the browser does recognise as valid is found, it stops execution of the code block following it.
Only one of the vendor-prefixed selectors you are using will exist in each browsers (for example WebKit browsers do not have the Mozilla and Microsoft vendor-prefixed selectors); therefore you will never be able to execute that block as there is no browser where all three pseudo-selectors are valid.
However...
... you can simply use three different blocks. For example, this should work:
input[type=text]:focus::-webkit-input-placeholder {
color: green;
}
input[type=text]:focus::-ms-input-placeholder {
color: green;
}
input[type=text]:focus::-moz-placeholder {
color: green;
}
<input type="text" placeholder="Hello, world!">
If you have a lot of code, you could use a preprocessor like LESS or SASS to dynamically put the same code inside each block.

The reason why you can't group these selectors is because as soon as a browser comes across an unknown selector it stops execution for that block of code.
Vendor-specific selectors are only known to the browser that supports them. If you group them, every browser will stop executing that block of code either at the first selector in the group or at the second.
In this example:
input[type=text]::-webkit-input-placeholder, /* Chrome / Opera / Safari */
input[type=text]::-moz-placeholder, /* Firefox 19+ */
input[type=text]:-ms-input-placeholder, /* Edge/IE 10+ */
input[type=text]:-moz-placeholder { /* Firefox 18- */
color: green;
}
Google Chrome, Safari, and Opera will recognize the first selector, but they will stop executing this block of code at the second selector, which is only valid in a Firefox browser. The other browsers will stop execution at the very first selector.
Therefore each of these selectors must have their own block of code.

Related

How do I create a CSS mixin using the new `part` syntax?

I want to apply a number of CSS rules to different selectors, without creating additional selectors. In SCSS, this would be typically done with a mixin, eg:
#mixin gradient-text {
color: transparent;
background-clip: text;
-webkit-background-clip: text;
background-image: linear-gradient(
350deg,
var(--dark-blue),
var(--teal),
var(--bright-green)
);
}
Reading around the internet, there's lots of references to making mixins with the CSS apply syntax, but
https://caniuse.com/sr_css-apply mentions:
#apply was briefly supported behind a flag in Chromium but has since been abandoned in favor of the ::part() selector.
Reading about CSS part though it seems like it's not possible to use CSS part without modifying my HTML and using web components, which have their own issues.
Is it possible to do a mixin in CSS, without modifying my HTML or JS, using part?
According to the MDN article you linked to, ::part can only match elements within a shadow tree. Additionally, the spec for the ::part states
The ::part() pseudo-element only matches anything when the originating element is a shadow host.
Thus, if you wanted to leverage this pseudo-element for CSS mixins, you'd be better working with (developing) a native web component library. You may be able to use the corresponding part HTML attribute outside of the Shadow DOM to implement CSS mixins depending on your requirements.
When in doubt the best thing is to experiment. Here is an example of using ::part() and part (HTML attr) inside and outside of a shadow DOM. Best to test browser support on part as it is a relatively new technology. Moreover, seems there is still ongoing questions about how multiple ident's should be supported, if at all.
customElements.define('custom-thing', class CustomThing extends HTMLElement {
constructor() {
super()
const root = this.attachShadow({ mode: 'closed'})
root.append(document.getElementById('custom').content.cloneNode(true))
}
})
[part~="a"] {
color: red;
}
[part~="b"] {
padding: 20px;
background: gray;
}
p::part(a) {
color: blue !important;
}
custom-thing::part(a) {
color: green;
}
custom-thing::part(a)::after {
content: 'A';
}
custom-thing::part(b) {
color: orange;
}
custom-thing::part(a b) {
/* does multiple ident values work? */
color: blue;
}
<p part="a b">part</p>
<template id="custom">
<style>
p[part="a"] {
color: aqua;
}
</style>
<p part="a">part a</p>
<p part="b">part b</p>
<p part="a b">part a b</p>
</template>
<custom-thing></custom-thing>

how to ignore class prefix in css file

I see some e.g. div/button style in Chrome console like this:
/* Chrome browser styles tab */
.ItemClass1-0-3-171.ItemClass2-0-3-173: {
background-color: "red"
}
How do I define a new style in CSS ignoring that class numbers? because it can be a different number for other div/button on the page..
/* CSS file */
.ItemClass1.ItemClass2 {
background-color: "blue"
}
You can use two attribute contains selectors for this.
[class*="ItemClass1"][class*="ItemClass2"] {
background-color: red;
}
<p class="ItemClass1-0-3-171 ItemClass2-0-3-173">foo</p>
But keep in mind that this will also select elements with the class fooItemClass2.
You can use an attribute selector with a starts-with value to pick up anything that starts with ItemClass.
Note: This solution assumes ItemClass is the first classname and doesn't account for whether the element has both classes. For these reasons Sven's answer might better suit your needs.
[class^='ItemClass'] {
background-color: blue;
padding: 4rem;
}
<div class="ItemClass1-0-3-171.ItemClass2-0-3-173"></div>

#supports property syntax error

I was checking the #supports property and it worked for this code -
#supports(display: block) {
.message{
background: red;
}
}
here it is giving red background but the following code doesn't work
.message{
background: green;
#supports(display: block){
background: red;
}
}
in this case the background should be red but it is coming out green. I have checked this on chrome edge and even on codepen. What is the problem ?
At-rules can't be nested within style rules. Wherever you're seeing that nested #supports rule working must be using some kind of preprocessor.

Vendor prefixes in nested Less selector

I am trying to use Less as efficient as possible. Now I want to replace the color of a placeholder, which I normally in CSS would do like this:
input::-webkit-input-placeholder /* WebKit, Blink, Edge */
{
color: #000000;
}
input:-moz-placeholder /* Mozilla Firefox 4 to 18 */
{
color: #000000;
}
input::-moz-placeholder /* Mozilla Firefox 19+ */
{
color: #000000;
}
input:-ms-input-placeholder /* Internet Explorer 10-11 */
{
color: #000000;
}
Now I thought using nested selectors in Less I could use:
input{
&::-webkit-input-placeholder, /* WebKit, Blink, Edge */
&:-moz-placeholder, /* Mozilla Firefox 4 to 18 */
&::-moz-placeholder, /* Mozilla Firefox 19+ */
&:-ms-input-placeholder /* Internet Explorer 10-11 */
{
color: #000000;
}
}
Unfortunately that does not work like I expected. When I only use one selector (without the comma's) it works fine, but that means I would still have to make four nested selectors for each prefix, which is not efficient. How can I accomplish the effect of the first CSS block in Less with the less possible lines?
Note: the full code block is more extensive, with more nested rules. Of course for this example I could just comma all the selectors with just CSS - but I want it to work in a nested Less-selector.
Disclaimer: As always I don't recommend using Less mixins for vendor prefixing stuff. They are best left to libraries like prefix-free or Auto-prefixer. This answer is just to show how similar things can be handled using Less.
Like you've already found out (and mentioned in comments), grouping of vendor prefixed selectors will not work because the User Agent will drop the entire rule when it comes across a selector that it does not understand. You can read more about it in this answer.
This is not a problem with the Less compiler. It will compile and output the code as expected.
One way to avoid writing the four selector blocks again and again would be to put the vendor prefixed selectors into a mixin which accepts a ruleset as argument and then call it wherever required. Below is a sample code for your reference.
.placeholder(#rules){ /* no need to repeat, just copy paste this once in your code */
&::-webkit-input-placeholder /* WebKit, Blink, Edge */
{
#rules();
}
&:-moz-placeholder /* Mozilla Firefox 4 to 18 */
{
#rules();
}
&::-moz-placeholder /* Mozilla Firefox 19+ */
{
#rules();
}
&:-ms-input-placeholder /* Internet Explorer 10-11 */
{
#rules();
}
}
/* call it wherever required */
input{
.placeholder({
color: red;
})
}
input.somethingelse{
.placeholder({
color: black;
padding: 4px;
})
}

JavaFX CSS hover vs onMouseEntered

I'm using JavaFX, and in my CSS I have
.button:hover{
-fx-background-color: red;
}
Which works. But when I try to use another property,
.button:onMousePressed {
-fx-background-color: red;
}
Or onMouseEntered (which I expected to be the same behavior as hover), nothing happens. Is there something fundamentally different about how these work?
Those simply aren't valid CSS pseudoclasses for a button. You are probably looking for
.button:armed {
/* ... */
}
The valid pseudoclasses are listed in the CSS documentation

Resources