Conditional pseudo-selectors
Conditional statements are a fundamental part of any programming language, and in Active CSS they can be handled in a similar way to CSS.
Important note for this section of the docs
Since version 2.7.0 you can now use the @if statement, which is covered in the Control Flow section of the documentation. This page only covers the use of conditionals when they are being attached to event selectors. The examples that are contained in this section mostly use the original event selector syntax, but would often be easier to write, quicker to run, and more easy to read, using @if. Used with @if, the syntax for conditionals is essentially the same - you can (optionally) just remove the if- part at the beginning of the conditional to use it in an @if statement. And "not-" conditionals, like "not-if-empty", become "not-empty" or "!empty".
Description
CSS as a styling language has it's own unique syntax for handling conditional statements. CSS usually deals with a conditional scenario by altering the selector, such as .menuItem:not(.selected) {...}. You may not think of it this way, but there are, basically, "if" statements happening behind the scenes in the browser's internal code when pseudo-selectors are in play.
In Active CSS we have taken the same syntactical approach, and conditional declarations can be set up to work in the same way, and in Active CSS they can be attached to event selectors.
In CSS, the pseudo-selectors generally apply only to the main selector.
But in ACSS you can run actions and CSS commands depending on the state of other elements on the page that are completely disrelated to the main selector.
When conditionals are used as "pseudo-selectors", they can only be placed on the event selector (not target selectors), and always appear directly before the event itself. So ":click", ":mouseover", etc. must always be at the end. They should appear directly before the event and after any regular CSS pseudo-selectors if any are being used.
Conditions can be chained together in the event selector, similar to how conditionals are chained in CSS. Each conditional must be prefixed with a colon.
You can either use conditional functions directly in the event selector, in the style of CSS, like this:
myDiv:if-exists(#myOtherDiv):click {
... do something
}
Or if you have a function with similar parameters that you use a lot, you can create what is called simply a "conditional", which can contain multiple conditional functions or just one - and given a simple variable name for reference.
Conditional declarations go in your config file along with the rest of your code, in the same file or perhaps in a separate file.
To write the conditional, you make up a name for the conditional, and prefix it either with a question mark or "@conditional". Either syntax is fine. When the config is loaded, all "@conditional" syntax gets converted internally to the shorthand "?". Though you may prefer using "@conditional" in your config, as it can be easier to search for and more closely aligns to familiar CSS syntax.
In this example, we create a conditional entitled "myDivCheck". The subsequent event ".myButtons:myDivCheck:click" will only run if the element #myDiv can be found on the page:
@conditional myDivCheck {
if-exists: #myDiv;
}
.myButtons:myDivCheck:click {
.myModal {
remove-class: .hide;
render: "<p>#myDiv is on the page.</p>";
}
}
The conditional function "if-exists" in the above example is a built-in boolean action.
This method of setting up conditional statements as single entities means that you can re-use conditional statements.
You can separate out your conditional statements in your code and put them in one place, or put them right next to where you are using them, or in a separate file as you wish.
The scope of conditionals
Conditionals are scoped to either a privately scoped component, a shadow DOM component, or the document scope, depending on where they are declared. So you can have the same conditional name used in different areas of the config, and they will not clash. They are used in a component in exactly the same way as the regular config. See the Tic Tac Toe web private components example to get an example of this - look out for the @conditional line inside the component config.
Built-in boolean actions
There are a number of conditional functions built-in to Active CSS.
Each conditional used in an event selector will return true or false depending on the result of the conditional.
If the return value is true after a conditional has run, the conditional is said to have been passed, and the next conditional will be checked if there is one there.
You can subsitute in JavaScript expressions prior to the conditional being run, if you need to insert a string or boolean value on-the-fly (see if-var-true for an example).
As soon as a conditional function fails, the event selector declaration that the conditional is attached to will be skipped, and the event will not be run. It failed to pass the conditional checks.
To see all the built-in boolean functions, see the list of conditional functions in this section of the documentation.
! and "not-" operator
All conditional functions set up in Active CSS can be used with a ! (not) operator, or a "not-" prefix, which will allow the conditional function to pass if the result is FALSE.
For example, the following conditional will only pass if the #myDiv element is not present on the page:
?myDivNotThere {
!if-exists: #myDiv;
}
or you can do this:
?myDivNotThere {
not-if-exists: #myDiv;
}
Why both "!" and "not-", and not just a single operator?
Version 1 of Active CSS only had the "!" operator. When version 2 came out, it was possible to add conditional function directly into the event selector. But it looked weird having an exclamation point in the CSS selector, so the "not-" prefix was added to the core to more align with CSS syntax. It just looks nicer and makes more sense when you read it in the event selector. But the shorthand "!" is still there and won't be removed as some people prefer shorthand coding.
Note: "!" and "not-" will also work with any custom conditional functions that you create yourself with no additional work on your part. In creating conditional functions you must always make sure that your desired result will return true (as a boolean) if the condition is met, and false (as a boolean) if the condition fails.
Multiple conditional functions
Often all you need is just one conditional function, but you can have multiple conditional functions if you need them. You can either chain the conditional functions directly into the event selector, or if you have a lot of them you may wish to create a dedicated conditional for them.
To do this, put the conditional functions on different lines in the conditional declaration. Also remember that all actions in Active CSS must end in a semi-colon.
All conditional functions must pass as true in order for events to run, so in the example below the scrolltop of the event selector must be greater that 240 pixels and #dave must not be visible. If it passes this check, then the event selector actions will run:
@conditional okToContinue {
if-scrolltop-greater: 240;
!if-visible: #dave;
}
Grouping conditional names
If you have the same condition being used multiple times, you can group conditions like you would do selectors in CSS.
Active CSS code is always cumulative. If it is the config, it will get added to anything that already exists - it will never replace what is there.
For example:
?myDivExists {
if-exists: #myDiv;
}
?myDivExists, geoff, trevor {
if-visible: #dave;
}
Note that in this next example, the conditional "myDivExists" gets an additional check when it appears for the second time in the config.
You also can mix and match shorthand ? and longhand @conditional commands.
The above example is exactly equivalent to this:
?myDivExists {
if-exists: #myDiv;
if-visible: #dave;
}
@conditional geoff, trevor {
if-visible: #dave;
}
It is up to you if you want to group up conditionals, and it is up to you whether you want to use "@conditional" or the short-hand "?". For clarity you might not want to group conditionals like this. But if you have long, identical declarations, you could group them together as above. If you do group conditionals, you may find the "?" syntax quicker to read and type.
Media queries and conditionals
For ease in handling media queries, you can set up a custom media query conditional statement. This gives you the benefit of having the number of pixels or whatever in one place for future editing. Although Active CSS does support straight media query syntax as a wrap-around syntax like CSS, we have found that the following method of handling media queries can be easier to manage in development as we find it easier to see what is going on when we read the code, but this is a matter of taste or practicality:
@conditional smallDevice {
if-media-max-width: 720px;
}
.menu a:smallDevice:click {
/* do something */
}
Attribute values & property states
Both conditionals and selectors go on the same line in the event selector, so it makes sense to learn and use the native CSS equivalent, if there is one, rather than having to set up an additional conditional declaration.
If you want to check that a event selector has a certain attribute value, use something like ".menuItems[data-title="hello"]:click{...}". You can find all the information you need on CSS selectors on the interwebs.
Always try and use CSS selectors if you can - the result will be faster, and your code will be more concise.
You can also use CSS selector syntax for properties, such as :checked.
Below is a list of supported CSS pseudo-classes up to CSS Level 4 (not all browsers may support these yet):
- active
- any-link
- blank
- checked
- current
- default
- dir
- disabled
- drop
- empty
- enabled
- first-child
- first-of-type
- focus
- focus-visible
- focus-within
- future
- has
- hover
- indeterminate
- in-range
- invalid
- is
- lang
- last-child
- last-of-type
- link
- local-link
- not
- nth-child
- nth-column
- nth-last-child
- nth-last-column
- nth-last-of-type
- nth-of-type
- only-child
- only-of-type
- optional
- out-of-range
- past
- paused
- placeholder-shown
- playing
- read-only
- read-write
- required
- root
- scope
- target
- target-within
- user-error
- user-invalid
- valid
- visited
- where
If you see any pseudo-classes missing in the above list and it is supported and you need to use it - please let us know. We keep these updated in the core currently. So if your pseudo-class does not work and it is not in the list, let us know asap and we will update the list as soon as we can.