Generalization in CSS selectors is possible? - css

I can write this selector condition:
h1:not(footer)
, h2:not(footer)
, h3:not(footer)
, h4:not(footer)
, h5:not(footer)
, h6:not(footer) {
font-family: "Luckiest Guy";
}
but, exists anything easy to use like:
(h1, h2, h3, h4, h5, h6):not(footer) {
font-family: "Luckiest Guy";
}

This is where css preprocessor comes in, you can add variables and functions for efficient development. It also makes your code more organized and clean.
Try using SASS, you can do that with:
h1, h2, h3, h4, h5, h6 {
&:not(footer) {
font-family: "Luckiest Guy";
}
}
It will compile this and generate a new css file that is equivalent to the code above.
Link to sass: https://sass-lang.com/

Related

Transform CSS at build time. Can I do this with SASS or LESS?

I am completely new with either SASS and LESS (I know the concept, but never used them), but I know CSS. This question is about is the idea or direction is good, or should I look for other?
I am facing the the following task: I need to have create .CSS files as usual except all selectors must be selective within a single div (with its id). So the normal reset should be like:
/* ...*/
div#mydivid h1, div#mydivid h2, div#mydivid h3, div#mydivid h4, div#mydivid div#mydivid h5 {
/* ...*/
}
instead of:
/* ...*/
h1, h2, h3, h4, h5 {
/* ...*/
}
/* ...*/
Obviously I could manually maintain this, and rewrite my (and other's) standard CCS-s, but I am hoping that I can still write my CSS (and use existing ones) in the standard way, and a build time a preprocessor generates the transformed ones, what I will actually link to my pages.
Is this possible? Has anybody better idea?
(I do not think it should matter but this is VS 2013, and C# / ASP.NET)
Using Less or SASS/SCSS you may wrap the entire stylesheet into a div. But SASS has a feature to break out of any wrappers called #at-root.
You may even wrap the includes to get a wrapper around any stylesheets (SCSS):
div#mydivid {
#include _layout.scss
#include _module1.scss
}
/* or */
div#mydivid {
#{headings(1,6)} {
color: #333;
}
}
The latter results in:
div#mydivid h1,
div#mydivid h2,
div#mydivid h3,
div#mydivid h4,
div#mydivid h5,
div#mydivid h6 {
color: #333;
}

multiple nested selectors with variables in Less

I want to build some CSS along these lines:
h1,h2,h3,h4,h5,h6 {some rule}
h1 a,h2 a,h3 a,h4 a,h5 a,h6 a {color: inherit;}
h1 span,h2 span,h3 span,h4 span,h5 span,h6 span {another rule;}
It would be useful if I could create a variable like this:
#headings: h1,h2,h3,h4,h5,h6;
and then maybe do something like this:
#{headings} {
& a {color: inherit;}
}
Unfortunately this gives me:
h1, h2, h3, h4, h5, h6 a {
color: inherit;
}
Is what I want possible? This is a simple version of what I want to do but I would also find useful for working with HTML input types and other instances of multiple selectors that often appear together.
Use a Ruleset
If you define your heading group as a ruleset with a mixin call to set properties with, then you can do this:
#headings: {h1,h2,h3,h4,h5,h6 {.setProps()}};
& {
.setProps() {
& {
some: rule;
}
a {
color: inherit;
}
span {
another: rule;
}
}
#headings();
}
I've isolated the whole thing inside & just so the .setProps() can be localized (it would work without it, but it would be setting the .setProps() globally. Also, the nested & {} bracketing is not necessary, but I find that it helps show what the "default" for the #headings is going to be.
This can be used sequentially, if desired, like so:
& {
.setProps() { some: rule; }
#headings();
}
& {
.setProps() { a {color: inherit;}}
#headings();
}
& {
.setProps() { span {another: rule;}}
#headings();
}
Both will output like so:
h1,
h2,
h3,
h4,
h5,
h6 {
some: rule;
}
h1 a,
h2 a,
h3 a,
h4 a,
h5 a,
h6 a {
color: inherit;
}
h1 span,
h2 span,
h3 span,
h4 span,
h5 span,
h6 span {
another: rule;
}
#1
Just yet one more solution in addition to #helderdarocha's answer and those given in https://stackoverflow.com/a/23954580/2712740. Maybe be this one could look a bit more clear:
// define header list as usual just
// put a mixin call with some predefined name there
h1, h2, h3, h4, h5, h6 {.headings}
// now to add styles/childs to the header list just add the mixin definitions:
.headings() {
some: rule;
}
.headings() {
a {color: inherit}
}
.headings() {
span {another: rule}
}
// etc.
The limitation of this solution is that h1, h2, h3 ... {} and .headings should be defined at the same level. Additionally, it's important to keep in mind that all these styles will output to CSS at the point of h1, h2, h3 ... {} definition not at the point of .headings definitions, so it may break your cascading overrides if you have some).
#2
The alt. solution I'm copy-pasting from https://stackoverflow.com/a/23954580/2712740 #3, basicaly it's the same as #1 but w/o its limitations (just having more special scary symbols):
// the "variable":
.headings(#-) {
h1, h2, h3, h4, h5, h6
{#-();}}
// usage:
.headings({
some: rule;
});
.headings({
a {color: inherit}
});
.headings({
span {another: rule}
});
//etc.
If you have these variables and selectors:
#headings: h1,h2,h3,h4,h5,h6;
#{headings} {
some-rule: rule;
}
.headings { // this is a placeholder
color: inherit;
}
h1 span {
other-rule: rule;
}
You can use this mixin to generate the code you want:
.mixin(#headings; #count) when (#count > 0) {
.mixin(#headings; #count - 1);
#heading: extract(#headings, #count);
#{heading}{
& a:extend(.headings) {}
& a:extend(h1 span) when not (#heading = h1) {}
}
}
Calling:
.mixin(#headings, length(#headings));
will generate:
h1, h2, h3, h4, h5, h6 {
some-rule: rule;
}
.headings,
h1 a,
h2 a,
h3 a,
h4 a,
h5 a,
h6 a {
color: inherit;
}
h1 span,
h2 a,
h3 a,
h4 a,
h5 a,
h6 a {
other-rule: rule;
}

How to set Bootstrap #font-family-base?

Bootstrap docs say:
Use the #font-family-base, #font-size-base, and #line-height-base attributes as our typographic base.
Does this mean there is a CSS variable called #font-family-base?
How can I set this in CSS to change the font for my whole page?
For Bootstrap 3 open up your custom.css and
body,
h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
font-family: "Ubuntu", Helvetica, Arial, sans-serif!important;
}
It's not a CSS variable, it's a LESS variable.
You can find (and edit) them in variables.less.
Visit the Bootstrap docs on customization - you can change several variables in Typography section, for instance #sansFontFamily, #serifFontFamily, #monoFontFamily, #baseFontSize, etc
See below, place at the top of your CSS file.
#import url(http://fonts.googleapis.com/css?family=Open+Sans:400,700);

Can I target all <H> tags with a single selector?

I'd like to target all h tags on a page. I know you can do it this way...
h1,
h2,
h3,
h4,
h5,
h6 {
font: 32px/42px trajan-pro-1,trajan-pro-2;
}
but is there a more efficient way of doing this using advanced CSS selectors? e.g something like:
[att^=h] {
font: 32px/42px trajan-pro-1,trajan-pro-2;
}
(but obviously this doesn't work)
No, a comma-separated list is what you want in this case.
If you're using SASS you could also use this mixin:
#mixin headings {
h1, h2, h3,
h4, h5, h6 {
#content;
}
}
Use it like so:
#include headings {
font: 32px/42px trajan-pro-1, trajan-pro-2;
}
Edit: My personal favourite way of doing this by optionally extending a placeholder selector on each of the heading elements.
h1, h2, h3,
h4, h5, h6 {
#extend %headings !optional;
}
Then I can target all headings like I would target any single class, for example:
.element > %headings {
color: red;
}
It's not basic css, but if you're using LESS (http://lesscss.org), you can do this using recursion:
.hClass (#index) when (#index > 0) {
h#{index} {
font: 32px/42px trajan-pro-1,trajan-pro-2;
}
.hClass(#index - 1);
}
.hClass(6);
Sass (http://sass-lang.com) will allow you to manage this, but won't allow recursion; they have #for syntax for these instances:
#for $index from 1 through 6 {
h#{$index}{
font: 32px/42px trajan-pro-1,trajan-pro-2;
}
}
If you're not using a dynamic language that compiles to CSS like LESS or Sass, you should definitely check out one of these options. They can really simplify and make more dynamic your CSS development.
The new :is() CSS pseudo-class can do it in one selector.
For example, here's how you could target all headings inside a container element:
.container :is(h1, h2, h3, h4, h5, h6)
{
color: red;
}
Most browsers now support :is(), but keep in mind that most browsers made before 2020 didn't support it without a prefix, so be careful about using this if you need to support older browsers.
In some cases, you may instead want to use the :where() pseudo-class, which is very similar to :is() but has different specificity rules.
SCSS+Compass makes this a snap, since we're talking about pre-processors.
#{headings(1,5)} {
//definitions
}
You can learn about all the Compass helper selectors here:
Here is my attempt to solve this problem with (modern) CSS only.
Context : Inside of Joplin (very nice note taking app, link), there is an userfile.css in which you can write your custom CSS for display and export of markdown notes.
I wanted to target all headings directly after (adjacent sibling) certain tags, namely p, ul, ol and nav to add a margin in between. Thus :
p + h1,
p + h2,
p + h3,
p + h4,
p + h5,
p + h6,
ul + h1,
ul + h2,
ul + h3,
ul + h4,
ul + h5,
ul + h6,
ol + h1,
ol + h2,
ol + h3,
ol + h4,
ol + h5,
ol + h6,
nav + h1,
nav + h2,
nav + h3,
nav + h4,
nav + h5,
nav + h6 {
margin-top: 2em;
}
WOW. Very long. Such selectors.
I then came here, learnt, and tried :
p + :is(h1, h2, h3, h4, h5, h6),
ul + :is(h1, h2, h3, h4, h5, h6),
ol + :is(h1, h2, h3, h4, h5, h6),
nav + :is(h1, h2, h3, h4, h5, h6) {
margin-top: 2em;
}
Hmm. Much shorter. Nice.
And then, it struck me :
:is(p, ul, ol, nav) + :is(h1, h2, h3, h4, h5, h6) {
margin-top: 2em;
}
Yay, this also works! How amazoomble!
This might also work with :where() or other CSS combinators like ~ or even (space) to create "matrix" of CSS selectors instead of very long lists.
Credits : all the answers on this page referencing the :is() selector.
Stylus's selector interpolation
for n in 1..6
h{n}
font: 32px/42px trajan-pro-1,trajan-pro-2;
The jQuery selector for all h tags (h1, h2 etc) is " :header ". For example, if you wanted to make all h tags red in color with jQuery, use:
$(':header').css("color","red")
July 2022 update
The future came and the :is selector is what you're looking for as described in this answer given in 2020 by #silverwind (now the selected answer).
Original answer
To tackle this with vanilla CSS look for patterns in the ancestors of the h1..h6 elements:
<section class="row">
<header>
<h1>AMD RX Series</h1>
<small>These come in different brands and types</small>
</header>
</header>
<div class="row">
<h3>Sapphire RX460 OC 2/4GB</h3>
<small>Available in 2GB and 4GB models</small>
</div>
If you can spot patterns you may be able to write a selector which targets what you want. Given the above example all h1..h6 elements may be targeted by combining the :first-child and :not pseudo-classes from CSS3, available in all modern browsers, like so:
.row :first-child:not(header) { /* ... */ }
In the future advanced pseudo-class selectors like :has(), and subsequent-sibling combinators (~), will provide even more control as Web standards continue to evolve over time.
Plain CSS
With plain css you have two ways. This targets all the heading elements wherever they are inside the page (as asked).
:is(h1, h2, h3, h4, h5, h6) {}
This one does the same but keeps the specificity to 0.
:where(h1, h2, h3, h4, h5, h6) {}
With PostCSS
You can also use PostCSS and the custom selectors plugin
#custom-selector :--headings h1, h2, h3, h4, h5, h6;
:--headings {
margin-top: 0;
}
Output:
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
}
You could .class all the headings in Your document if You would like to target them with a single selector, as follows,
<h1 class="heading">...heading text...</h1>
<h2 class="heading">...heading text...</h2>
and in the css
.heading{
color: #Dad;
background-color: #DadDad;
}
I am not saying this is always best practice, but it can be useful, and for targeting syntax, easier in many ways,
so if You give all h1 through h6 the same .heading class in the html, then You can modify them for any html docs that utilize that css sheet.
upside, more global control versus "section div article h1, etc{}",
downside, instead of calling all the selectors in on place in the css, You will have much more typing in the html, yet I find that having a class in the html to target all headings can be beneficial, just be careful of precedence in the css, because conflicts could arise from
Using scss you can loop through 6 and append to an empty variable $headings using a comma separator
$headings: ();
#for $index from 1 through 6 {
$headings: list.append($headings, h#{$index}, $separator: comma);
}
#{$headings} {
--default: var(--dark);
color: var(--default);
}
Thanks #steve

CSS selector for multiple sub-elements

Let's say I have this table:
<table class="live_grid">
<tr>
<td>
<h3>Something!</h3>
</td>
</tr>
</table>
If I want to style the <h3> within the table, I can use this CSS selector:
.live_grid h3 {
}
This works fine. The trouble pops up if I want to style all headings in that table. I have tried this:
.live_grid h1,h2,h3,h4,h5,h6 {
}
This seems to match headings that are not within my table with the class of live_grid.
I'm sure this is a simple problem and right in front of me. Can you point out what I'm doing wrong?
Modern Option
Note: it may not be compatible with older browsers:
.live_grid :is(h1,h2,h3,h4,h5) {
/* style here */
}
See here for more information about :is(): https://developer.mozilla.org/en-US/docs/Web/CSS/:is
Standard Option:
If you want to style all the headers in that class, you have to do it like this (which could also be done without the line breaks). Notice each selector has .live_grid in it:
.live_grid h1,
.live_grid h2,
.live_grid h3,
.live_grid h4,
.live_grid h5,
.live_grid h6 {
/* style here */
}
When you comma separate things, they're independent of each other - hence the need to reference the class again.
For example:
#myDiv1, .live_grid, #myDiv2 {
color: blue;
}
This would set the text-color for everything in the #myDiv1 element, everything in the #myDiv2 element, and everything in the .live_grid element to having text color blue.
This also explains the reason your CSS is matching all the headers - you're referencing them individually, separated by commas - there is no selector for their containing element(s).
CSS pre-processor option
Or, you can always go with something like LESS or SASS which allows you to write nested rules something like this:
#live_grid {
h1, h2, h3, h4, h5, h6 {
/* style here */
}
}
Custom class option
Lastly, you could add a class to all of your headers and just refer to that class:
<-- HTML -->
<h1 class="custom-header">Title of Blog Post</h1>
<h2 class="custom-header">Subtitle of Blog Post about Pizza</h2>
/* CSS */
.custom-header {
/* style here */
}
.live_grid h1,
.live_grid h2,
...
you get the idea
Unfortunately, you'll need to target each heading separately, or just assign a class to it.
.live_grid h1,
.live_grid h2,
.live_grid h3,
.live_grid h4,
.live_grid h5,
.live_grid h6 {
}
I would just assign a class to the heading, or be specific about which headings you actually want to target.
Try this one:
.live_grid h1,
.live_grid h2,
.live_grid h3,
.live_grid h4,
.live_grid h5,
.live_grid h6 {}
The code
.live_grid h1,h2,h3,h4,h5,h6 {}
will only select the h1 that is with in .live_grid. Use
.live_grid h1,.live_grid h2,.live_grid h3,.live_grid h4,.live_grid h5,.live_grid h6 {}
From Adam Roberts' "Selector Grouping":
We can think of the comma as a logical OR operator, but it’s important to remember that each selector in a group is autonomous. A common beginner’s mistake is to write groups like this:
#foo td, th {
⋮ declarations
}
A beginner might think that the above declaration block will be applied to all td and th elements that are descendants of the element with an ID of "foo". However, the selector group above is actually equivalent to this:
#foo td {
⋮ declarations
}
th {
⋮ declarations
}
To achieve the true goal, write the selector group as follows:
#foo td, #foo th {
⋮ declarations
}
each heading tag has to be qualified:
.live_grid h1, .live_grid h2, .live_grid h3, .live_grid h4, .live_grid h5, .live_grid h6
That's one of the things that sucks about CSS. If you want CSS to suck less you can use http://sass-lang.com/ and it will look like:
.live_grid {
h1, h2, h3, h4, h5, h6 {
/* styles here */
}
}
.live_grid h1,
.live_grid h2,
.
.
.
.live_grid h6 { //now add your style here }
Another solution could be to add a special class for every h element you want to your html markup, and then, in your CSS, you can write somthing like this:
.live_grid .myHeader
{
/* your styling */
}

Resources