Page 1 of 1

CSS - Learning Out Loud

Posted: Mon Oct 21, 2024 5:31 am
by heatherbell
Received this question recently:
"How to apply rounded-pill to all my buttons?"
rounded-pill is a Bootstrap class that can be added to elements to give, what some might consider, a modern rounded look to buttons, like this for example:

Screenshot 2024-10-21 052113.png

rounded-pill automatically applies a large 50rem border-radius to all 4 corners to achieve that look.
Of course, this class name could be added to copies of all the relevant tpl_ files and saved in a template to achieve this.
However, CSS Rules could be used in the template user.css file to achieve the same with much less effort.
Sharing here in case it's useful to others.

In a current default install, we have this on product page, for example:

Screenshot 2024-10-21 051444.png

All the relevant buttons in a default install have, within their class attribute, class names like btn-info, btn-success etc.
For example, something like <a class="btn btn-success">
This makes it easier to target those classes with rules that change their border-radius.

Let's start with:

Code: Select all

[class*=" btn-"] {
  border-radius: 50rem;
}
So, what does that mean?

The whole piece of code is a CSS Rule, the first part before the curly braces is the Selector (multiple comma separated Selectors could be used) and the part within the curly braces is the Declaration of the Properties, ending with a colon and their Values, ending with a semi-colon (multiple Declarations could be used within the curly braces).

The square brackets in this case mean it is an Attribute Selector, so we have: [class] which means "target the class attribute of all elements".

The next part *= is called a substring operator, basically it means "contains", so we have: [class*=] which means "target the class attribute of all elements that contains".

The next part " btn-" defines what we're looking for, so we finally have: [class*=" btn-"] which means "target the class attribute of all elements that contains btn-". The space before the btn- is important so we are targeting names like btn-xyz and not somenamebtn-xyz.

The Declaration here is border-radius: 50rem; which is what rounded-pill does.

Let's save this to the user.css file on the server and hard refresh the page.

Screenshot 2024-10-21 062228.png

Yay! It works!
Browsing around the site shows it has changed the buttons everywhere as expected.

If it had not worked, first check would be that the user.css file on the server has been updated. We use FTP file transfer software and it (and us) are fallible :(
Next, there might be other CSS that is taking priority so change the Declaration to border-radius: 50rem !important; to give it priority.

This CSS Rule works with Bootstrap v.4 and v.5.
Caveat: this is using a default installation.

Re: CSS - Learning Out Loud

Posted: Mon Oct 21, 2024 2:18 pm
by heatherbell
Answering one question just leads to another.
"How to apply rounded-pill only to specific buttons?"
Anyway, might as well share the answer here in case it helps others.

So now, we already know what we mean by CSS Rules, Selectors and Declarations.

In this case, first specifically identify our target.
To do this, we could look at the Source Code of the page (right click on the page and click View page source) or use the browser Developer Tools to do the same.
Using either method gives the HTML output of the page which can be easier for some than looking in the files which are often written using PHP or something else.

So, view the Page Source Code for a page that shows the Add To Cart button which we will use here to show 2 examples. Scroll through it looking for the likely target.

This is seen:

Screenshot 2024-10-21 135538.png

Knowledge of coding languages is not required to quickly notice that this is the target, thanks to all the helpful descriptive class attributes that have been included by those clever Core Developers!
The screenshot does not show all the code but shows what concerns us.

Notice the 1st <div> element which contains the rest of the code. This could be regarded, in this case, as a Parent (it could also be thought of as a Child and Descendant of other Parents but that doesn't matter here).

Notice the 2nd <div> element. This could be regarded, in this case, as a Child and a Descendant of the first Parent <div> element.

Now notice our target, the <button> element. This could be regarded, in this case, as a Child of the 2nd <div> element and a Descendant of the 1st <div> element.

The first <div> element has been given a class attribute which is entirely unique in the Core Code, pi-buy-button (thanks to those clever Core Developers again!). It will not exist anywhere else and so provides the means to target CSS with laser-like precision.

Too much information? Maybe but this not only helps explain the answer to the original question but also might pre-empt further questions!

CSS provides many ways of achieving the same outcome so let's look at some possible solutions.

The target <button> has a class attribute, btn-success.
So, first, let's target the button with:

Code: Select all

.btn-success {
  border-radius: 50rem;
}
The Selector in this code is .btn-success. The preceding point/period/full-stop means it is a Class Selector. The code means "target all elements that have btn-success in their class attributes".

Let's save this to the user.css file on the server and hard refresh the page.

Yay!

Screenshot 2024-10-21 145300.png

This has worked and changed the Add To Cart button without changing the buttons in the Quantity Select above it.
Looking at the footer of the page we see that the buttons there have also changed because they have btn-success in their class attributes.

Screenshot 2024-10-21 145722.png

So, next, let's specifically target the Add To Cart button and no other.
We have seen that the button is a Descendant (not a direct Child) of that 1st <div> that has a unique class attribute of pi-buy-button.

So we can use this:

Code: Select all

.pi-buy-button .btn-success {
  border-radius: 50rem;
}
Here the Class Selector has 2 class attributes separated by a space. That space between them is important. It means "target all elements that have btn-success in their class attributes that are descendants of all elements that have pi-buy-button in their class attributes".
Well, there's only 1 element in the whole of Core Code that has pi-buy-button in their class attributes so this should be a winner!

Let's save this to the user.css file on the server and hard refresh the page.

Yay! Won't put another screenshot here but be assured, now the change has only been applied to the Add To Cart button and nowhere else. #loveCSS > .works-first-time { animation: dance 2s infinite; } :D

Now just to demonstrate another example using a different method that could be useful in other scenarios.

We've seen the hierarchy of the elements in this code already, that is:
1st <div> which has a direct child 2nd <div> which has a direct child <button>

We can target that relationship using:

Code: Select all

.pi-buy-button > .d-grid > .btn-success {
  border-radius: 50rem;
}
Here the Class Selector has 3 class attributes, each separated by a >.
It means "target all elements that have btn-success in their class attributes that are a direct child of all elements that have d-grid in their class attributes that are a direct child of all elements that have pi-buy-button in their class attributes".

Again, the pinpoint specificity of this targeting means the change will only apply to the Add To Cart button and no other.

Having explained all that, of course, if we look again at this:

Screenshot 2024-10-21 135538.png

We can see that, very usefully, the Add To Cart button has its own unique class, btn-buy, not used anywhere else in core so that could be used to target the button directly which is the easiest and best way of targeting it, so:

Code: Select all

.btn-buy {
  border-radius: 50rem;
}
Caveats: this is using a default installation.