Relative CSS Selectors

CSS selectors are frequently used with Sircl, to refer to a target of page part requests, to name the object of Event-Actions, etc. Sircl extends the syntax of CSS selectors with the capability to refer to elements relatively to the current element.

Introduction

Standard CSS selectors are always absolute, they can match elements all over the page and are not restricted to a part of the page, or operate in context of an element. To describe styling from separate style sheets, this is not an issue or shortcoming from CSS.

In Sircl, CSS selectors are also used inside the HTML code to declare the target of an action. Though one can specify with CSS any set of individual elements by refering to them using unique identifiers, this may not be practical in all situation, particularly when a more component based approach is followed in the development of the application.

Sircl extends CSS selectors with the capability to refer to elements relatively to the position of the element where the CSS selector is written on.

This reference

To refer to the element self, holding the CSS selector, the extended CSS syntax supports the :this keyword. When used, the :this keyword cannot be used within a more complex expression without using the rescoping operator.

<form target=":this">
  ...
</form>

Note that the target class does exactly that: it adds a target attribute with the value ":this".

Using the :this keyword, we can refer to the current element without the need to use a unique identifier.

Parent reference

To refer to the parent of the element holding the CSS selector, the extended CSS syntax supports the :parent keyword. When used, the :parent keyword cannot be used within a more complex expression without using the rescoping operator.

<div>
  <form target=":parent">
    ...
  </form>
</div>

In the above example, target refers to the DIV element.

The following example uses the | rescoping operator and the > children operator discussed below, to refer to the local FOOTER element:

<div>
  <form target=":parent |> FOOTER">
    ...
  </form>
  <footer></footer>
</div>

To refer to the grand-parent of an element, we can use the ":parent | :parent" relative CSS expression.

Using the :parent keyword, we can refer to the current element's parent without the need to use a unique identifier.

Form reference

To refer to the form the element holding the CSS selector belongs to, use the :form keyword. It will point to the form surrounding the element containing the expression.  When used, the :form keyword cannot be used within a more complex expression.

<form>
  <button type="button" onclick-disable=":form">Click me!</button>
</form>

When the element containing the :form expression has a form attribute, then the :form expression points to the form element refered to by the form attribute:

<form id="f1">
  <input type="text" />
</form>
<button type="button" onclick-disable=":form" form="f1">Click me!</button>

Children operator (>)

To refer to children of the element holding the CSS selector, use the > children operator. This operator must appear as the first item of a scoped CSS selector expression. If it is not the first item in the expression, it will be considered as the standard CSS child selector that only selects the direct children of the element.

In the following example, the onsubmit-disable attribute has a value of "> INPUT". The expression looks for all INPUT elements inside the form and disables them during submissions. Input form controls on other forms are not impacted:

<form onsubmit-disable="> INPUT">
  <p><input type="text" placeholder="Name" /></p>
  <button type="submit">Submit</button>
</div>

The ">" character is legal in attribute values. Alternatively, you can also use the entity representation "&gt;".

Closest operator (<)

To refer to the element self holding the CSS selector or the closest parent, use the < operator. This operator must appear as the first item of a scoped CSS selector expression.

In the following example, the onclick-hide attribute has a value of "< DIV" (the space is not required). The expression looks up, starting from the button element where the expression is used, for the first DIV element it encouters. It therefore matches the inner DIV element but not the outer DIV element:

<div>
  <p>This message will not be hidden.</p>
  <div>
    <p>Press the following button to hide this message.</p>
    <button type="button" onclick-hide="< DIV">Hide message</button>
  </div>
</div>

The "<" character is legal in attribute values. Alternatively, you can also use the entity representation "&lt;".

Rescoping operator (|)

By default, the scope of a relative CSS selector is the element on which the CSS selector expression appears. Using the rescoping operator |, a new scope is established in the expression.

In the following example, the "<DIV | >INPUT[type='checkbox']" expression first selects the closest parent DIV element, then the rescoping operator | makes it the scope from now on. The remaining part of the expression is evaluated with the DIV as scope, resulting in all checkboxes in the DIV to match the selector:

<div>
  <button type="button" onclick-check="<DIV | >INPUT[type='checkbox']">Check all</button>
  <p><input type="checkbox"></p>
  <p><input type="checkbox"></p>
  <p><input type="checkbox"></p>
</div>

The rescoping operator is typically followed by the children or closest operator, as scoping is typically only usefull when using relative operators.

The following example is more complex and shows the rescoping operator in combination with both children and closest operators:

<div class="option-set">
  <div>
    <a href="null" onclick-hide=":this, < .option-set | > input[type=checkbox]:not(:checked) | < div" onclick-show="< div | > .unhide-link" class="hide-link">Hide unchecked</a>
    <a href="null" onclick-hide=":this" onclick-show="< .option-set | > input[type=checkbox] | < div, < div | > .hide-link" class="unhide-link" hidden>Show all options</a>
  </div>
  <div><label><input type="checkbox"/> Option 1</label></div>
  <div><label><input type="checkbox" checked/> Option 2</label></div>
  <div><label><input type="checkbox"/> Option 3</label></div>
  <div><label><input type="checkbox" checked/> Option 4</label></div>
</div>

The first link has following value for it's onclick-hide attribute:

:this, < .option-set | > input[type=checkbox]:not(:checked) | < div

This expression consists of two selectors separated by a comma. The first part of the expression, :this, refers to the link itself.

The second part looks up the closest .option-set, from there looks for unchecked checkboxes, and of those checkboxes takes the closest DIV elements.

As a result, clicking the link will hide the link itself as well as the closest DIV elements of unchecked checkboxes within the current .option-set.

The above example shows how relative CSS selectors can operate within a limited region of your page without the need for element id's. While multiple option-sets may exists within a page, the links to show or hide unchecked options, will act only within the local option-set.

Relative selector separator

In CSS selectors, the comma (",") counts as union operator to list multiple CSS selectors.

When using relative CSS selectors, the comma also resets the scope. When multiple expressions should use the same scope, repeat the scope operator after each comma. For instance, the following expression will match all children of type INPUT, SELECT or TEXTAREA: ">INPUT, >SELECT, >TEXTAREA". The > children operator is repeated for each part of the CSS selector.

Another example:

<form id="f1" onsubmit-disable=">:submit, :submit[form='f1']">
  <button type="button">Click me!</button>
</form>

The ">:submit, :submit[form='f1']" selector matches all :submit children of the current element (:submit is a standard CSS selector keyword that matches submit buttons), as well as all :submit elements all over the page, provided they have an attribute form with value "f1".

First match

CSS selectors can return multiple matches. Using the :nth(1) extension you can specify that only the first match should be considered.

In the following example, the :nth(1) extension is used to match only the closest (first) expandable region:

<div>
  <label onclick-toggleshow="<DIV|>.children:nth(1)">Root</label>
  <div class="children animate" hidden>
    <div>
      <label onclick-toggleshow="<DIV|>.children:nth(1)">+ Folder A</label>
      <div class="children animate" hidden>
        ...
      </div>
    </div>
      <div>
      <label onclick-toggleshow="<DIV|>.children:nth(1)">+ Folder B</label>
      <div class="children animate" hidden>
        ...
      </div>
    </div>
  </div>
</div>

Note that you can only refer to the first match with the value of 1, no other value is currently supported.

Limitations

While relative CSS selectors provide additional features, due to the simple parser used, some standard CSS selectors may not function correctly when used inside the HTML code to declare the target of an action. Especially CSS selectors that contain comma's between paranthesisses, as is possible with the :is() or :where() pseudo-classes, are known to fail.

Relative CSS selectors are however only available within HTML code to declare the target of an action of Sircl extensions. This limitation therefore does not conflict with regular CSS usages.

CSS expressions on STYLE elements and in stylesheets are not impacted by this limitation as they cannot use (and do not need) relative CSS selectors.

 

Loading...