How to Style Anvil Apps with CSS
Tags: python, tutorial, webdev, css
Published: 2022-05-13 16:05:54


### About Anvil
_[Anvil](https://anvil.works?utm_source=dev_to_css_guide) is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just build it all in Python. Get started with one of our tutorials or check out an example app. For more help, we have detailed developer documentation and a friendly Community Forum._

# Using CSS in Anvil

[Anvil](https://anvil.works?utm_source=dev_to_css_guide) lets you build web apps entirely in Python. You can build your UI by [dragging and dropping](https://anvil.works/articles/drag-and-drop-builder?utm_source=dev_to_css_guide) Python components and styling them with Python code. But if you want to have even more control over the appearance of your Anvil apps, you can use CSS.

[CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) is a language used to style web pages. This guide will provide an introduction to CSS and how we can use it to change the appearance of web pages. We'll see how we can target components on a web page with CSS and write rules to modify how those components look. You'll be able to test your skills with some challenges as we go along. We'll then experiment with CSS on the live [Anvil homepage](https://anvil.works?utm_source=dev_to_css_guide) using the developer tools built into your browser. Then, we'll work through an example of using CSS to customize the appearance of an Anvil app with the Material Design theme.

In this guide to using CSS in Anvil, we will:

1. Take a look at [HTML and its relationship to CSS](#html-and-css)
2. Examine [CSS syntax](#css-syntax) in more detail, including:
  * [Using selectors and classes](#selectors-and-classes)
  * [Combining selectors](#combining-selectors)
3. Use the browser's [developer tools](#using-the-developer-tools) on the Anvil homepage to:
  * [Select an HTML element](#selecting-an-element)
  * [Inspect the HTML code](#inspecting-the-html)
  * [Inspect the CSS code](#inspecting-the-css)
4. Learn more about [using CSS to style Anvil apps](#using-css-in-anvil-apps), including: 
  * [Applying CSS via Python](#applying-css-via-python)
  * [Writing CSS in theme.css](#writing-css-in-the-stylesheet)
  * [Using Anvil roles](#anvil-roles)


> _The best external resource for learning more about CSS and HTML is the [Mozilla Developer Network Web Docs](https://developer.mozilla.org/en-US/docs/Web/). The MDN Web Docs are an open-source project that provide reference guides and tutorials for web languages and technologies. They have detailed and clear resources for beginners and advanced users. I will frequently be linking to the MDN Web Docs in this guide._

## HTML and CSS

When we talk about **front-end web development**, we are talking about all the code that is responsible for displaying the visual part of a website or web app. When you load a web page, all the code associated with displaying the page is loaded into your browser, which is where the code runs. You can actually inspect this code and make local changes to it, which we will do with the Anvil homepage [later in this guide](#using-the-dev-tools).

In the traditional, non-Anvil, way of doing front-end development, [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML) is used to define the elements that make up a web page. [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) targets those elements and defines rules that dictate how they will appear on the page. When you drag-and-drop Anvil components onto a form, these components generate their own HTML. When you edit the component's properties, this generates CSS rules that target the HTML to style the component. 

HTML defines the elements on a page using "tags". The most basic HTML element is a `<div>`, which is just a generic container with no pre-defined styling. Very often, HTML elements are nested inside each other, just as in Anvil where we often nest components within [containers](https://anvil.works/beta-docs/client/components/containers) like [ColumnPanels](https://anvil.works/beta-docs/client/components/containers#columnpanel) and [FlowPanels](https://anvil.works/beta-docs/client/components/containers#flowpanel). For example, the following code defines a `<div>` and adds a button that says 'Submit' to the page:

```html
<div>
  <button>Submit</button>
</div>
```

With CSS, we can target the button and change the way it looks. The following code targets all buttons on the page, gives them a pink border and a gray background color:

```css
button {
  border: 1px solid pink;
  background-color: gray;
}
```

Next, we'll take a closer look at CSS and its syntax.

## CSS Syntax

With CSS, we can write rules that tell the browser what each component on our webpage should look like. CSS stands for **Cascading Stylesheet**. 'Stylesheet' refers to the document where the CSS styling rules are written, and 'Cascading' refers to the order in which CSS applies those styling rules. A CSS rule has three parts:

1. **Selector**: This 'selects' which HTML element or elements to apply the rule to.
2. **Property**: This is the feature of the element that will be targeted.
3. **Value**: Describes how the property will be rendered by the browser.

![Syntax of a CSS rule](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ab3kih9tj34c3ivvxzj6.png)

### Selectors and classes

In the previous example, we used CSS to target `<button>` elements. We did this by just writing the name of the tag and then defining the rule. This is called a **type selector**.

More often, we will target elements by giving them a **class**. Classes can be applied to as many HTML elements as we want. They are a way of applying the same style to multiple elements without repeating code. To add a class in HTML, we use the [`class` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class), and to use the **class selector**, we use `.` followed by the class name. 

Let's extend our previous example and give the button a class. Then, we can apply styling rules to that class. This way, we won't change every single button on the page, just the ones we want to target. Let's give the button a class called `submit` and apply the same styling rules just to that class:

```html
<div>
  <button class="submit">Submit</button>
</div>
```

```css
.submit {
  border: 1px solid pink;
  background-color: gray;
}
```

There are a number of different CSS selectors, which you can read about [here](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors#basic_selectors), but the most important for this guide are type and class selectors.


#### Try it yourself

Now it's your turn! Open the following code in CodePen and:

1. Give the second `<button>` a class called `cancel`
2. In the CSS, target that class and give it a different background color. 

_The `background-color` property can take some text-based values as well as hex and rgb values. Read more about `background-color` [here](https://developer.mozilla.org/en-US/docs/Web/CSS/background-color)_

{% codepen https://codepen.io/bcm628/pen/OJzQbYx %}


### Combining selectors

Selectors can also be combined in different ways. Let's look at how we can use more complex selectors to target the elements that we want.

#### Multiple selectors

Selectors can be grouped using a `,` in order to apply the same rules to multiple selectors. In the example below, elements with the `submit` or the `cancel` class will have a font size of 16px:

```css
.submit, .cancel {
  font-size: 16px;
}
```

#### Combining type and class selectors

A class selector can come directly after a type selector (without a space in between) to select elements of that type with that class. For example, we can use the following code to select `<button>` elements with the `submit` class (in case there are other types of elements that have the same class name):

```css
button.submit {
  border: 1px solid pink;
  background-color: gray;
}
```

#### Selecting descendents

Sometimes, we want to select elements that are nested inside other elements. For example, we might want to select buttons that are within a `card` container but no other buttons. A space between two selectors will select the elements that are descendants of the first element, while a `>` will select the elements that are a child (a direct descendant) of the first element. 

For example, the following HTML code defines a `<div>` element with the class `card`, which has another `<div>` with the class `buttons-div` nested inside. Inside that `<div>` are two `<button>` elements:

```html
<div class="card">
  <div class="buttons-div">
    <button class="submit">Submit</button>
    <button class="cancel">Cancel</button>
  </div>
</div>
```

Because the `<button>` elements are within the `<div>` with the `card` class, we can select them with the following CSS:

```css
.card button {
  border: 1px solid pink;
  background-color: gray;
}
```

However, the `<button>`s are not children of the `card` element because they are not directly nested within the `<div>`, but they are children of the `buttons-div` element. The first rule below will not select the `<button>`s whereas the second rule will:

```css
/* This won't select the buttons because they aren't children of the "card" <div> */
.card > button {
  border: 1px solid pink;
  background-color: gray;
}

/* This will select the buttons because they are children of the "buttons-div" <div> */
.buttons-div > button {
  border: 1px solid pink;
  background-color: gray;
}
```

For more on combining CSS selectors, see the [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors#combinators).


#### Try it yourself

Now it's your turn to combine CSS selectors to target elements. For the following challenges, open the code in CodePen, and don't add any new classes:

1. Select the second `<p>` and give it a [`color`](https://developer.mozilla.org/en-US/docs/Web/CSS/color) of pink. But keep the first `<p>` the way it is.
2. Give both the `submit` and `clear` buttons a `background-color` of `lightblue`, but leave the `cancel` button the way it is.
3. Give the `<div>` within the `card` a [`border`](https://developer.mozilla.org/en-US/docs/Web/CSS/border) property of `1px solid pink`

{% codepen https://codepen.io/bcm628/pen/wvpyJyv %}

_Stuck? [Check out a solution](https://codepen.io/bcm628/pen/jOYZBPO)._

### CSS properties

There are many different CSS properties that affect the layout and appearance of HTML elements, but it's beyond the scope of this guide to go over them in detail. For a list of all CSS properties and their corresponding values, see the [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Properties_Reference). In general, the MDN docs are the best place to learn more about CSS properties because they are detailed, give visual examples and are easy to follow. 

## Using the developer tools

Your browser has built-in developer tools to help you with front-end web development. These developer tools let you see all the code and files that are loaded into the browser when you open a web page. We can use the dev tools to inspect live code and make local edits, so they are an incredibly handy tool for debugging and experimenting with styling. 

Let's now use the dev tools to inspect the [Anvil homepage](https://anvil.works?utm_source=dev_to_css_guide) and see how HTML and CSS works out in the wild. 

### Selecting an element

When you load a web page, all the code used to display that page is loaded into the browser. This means that we can see the source code for any web page we can load in our browser, and we can make local changes to that code. Let's go to [Anvil's homepage](https://anvil.works?utm_source=dev_to_css_guide) and inspect the source code.

On the website, you can right click and choose 'Inspect' to bring up the browser's developer tools. (I use Google Chrome, but other browsers will have very similar dev tools). 

![Right-clicking on the homepage to inspect its code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ik4079yc8juhgjtzzrrp.png)

In the dev tools, click on 'Elements' to bring up the HTML and CSS for the page. Then click on the icon that looks like a square with a mouse cursor. This will allow us to select an element on the page and inspect its HTML and CSS.

![The Elements tab in the dev tools](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uk799u3j0p8amjqjut26.png)

Let's select the link that says "Start with a quick tutorial" on the Anvil website. This will highlight the relevant HTML in the dev tools and show us the CSS associated with that element. 

![Selecting the tutorial link on Anvil's homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7mfcxkzp7eiv1p6e4n2a.png)


### Inspecting the HTML

This is the HTML responsible for displaying that link:

![Screenshot of the dev tools showing the HTML code for a link on the Anvil homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e3l9nvhmvninze1uhs3t.png)

Here we have an [`<a>`, or anchor, element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a). Anchor elements are links, and the href attribute specifies the link's "target": usually, the URL to open when you click it The element also has a [`class` attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors). This particular element has two classes: `nowrap` and `tutorial`.

There is also an `<svg>` element nested inside the `<a>` element. The SVG is displaying the arrow in the link. Because the `<svg>` is nested directly inside the `<a>`, we can say that it is a child of the `<a>`.

### Inspecting the CSS

In the dev tools, we can see the CSS being applied to the element. The first rule looks like this:

![Screenshot of the dev tools showing the CSS code for a link on the Anvil homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sr5zth70tzmlvlvpkpfv.png)

The first line is the **selector**. This particular selector means "select the element with the `tutorial` class that is a descendent of an element with the `sub-hero-links` class which is a descendent of an element with _both_ the `col-hero` and `home` classes".

The next line of the CSS rule is the **property** we want to target and how it should be displayed. This particular rule is making the [`color`](https://developer.mozilla.org/en-US/docs/Web/CSS/color) of the element a light grey. 

We can actually modify the code directly in the dev tools. If I change the `color` of the link to be `lightgreen`, for example, we can see the change live in the browser. 

![Changing the color of the tutorial link from the browser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wgxdwx8yjx46tg8x6qk7.gif)

This is incredibly handy for styling apps. You can change and add CSS properties directly in the dev tools and immediately see the results. After playing with the CSS  styling in the browser, you can then go and actually change the source code of your app. The dev tools are also incredibly useful for debugging. If an element is not displaying how you think it should be, you can inspect it to see what CSS code is being applied to the element. Refreshing your browser will reload the page, and your local changes will be gone. This makes it easy to experiment without worrying about breaking the source code.


## Using CSS in Anvil apps

With Anvil, you can build the front-end of your web app entirely in Python. However, even when you are styling your apps in Python, your apps still use HTML and CSS. Anvil components generate HTML, and changing the properties of those components modifies the CSS for those components. In Anvil, we can change the appearance of components using Python via the [Properties Panel](https://anvil.works/beta-docs/editor#properties-panel?utm_source=dev_to_css_guide) or [client code](https://anvil.works/beta-docs/client/python?utm_source=dev_to_css_guide). Every Anvil app also has a stylesheet, so we can also write CSS for our app in the traditional way. This gives us more control over the appearance of an app.

To see how CSS is used in Anvil apps, let's [create a new Anvil app](https://anvil.works/new-build?utm_source=dev_to_css_guide) and choose the Material Design theme.

### Applying CSS via Python

Anvil components have [properties](https://anvil.works/docs/client/components#properties?utm_source=dev_to_css_guide) that can be modified via the Editor or through Python code. When we modify a component's properties, CSS is applied to the component's HTML in a [style attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/style). To see this in action, let's drag and drop a Button component onto our Anvil app and change its background color to gray in the Properties Panel:

![Drag and drop a Button onto the form and change its `background` in the Properties Panel.](https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/using-css/add-button.gif)

We can also change properties from code. Let's switch to code view and change the foreground color of our button in the `__init_` of our Form code. 

```python
class Form1(Form1Template):

  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    self.button_1.foreground = "white"
```

We can now run our app and inspect the page, just like we did with the Anvil homepage. If we select the button, we can see some HTML that looks like this:

```html
<button class="btn btn-default to-disable" ontouchstart=""
style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; background-color: gray ; color: white;">...</button>
```

Within the `style` attribute, we can see both the `background-color` property that we added in the Properties Panel and the `color` property (`foreground` in Anvil) that we added in the Form code. 


### Writing CSS in the stylesheet

We can also target Anvil components and write CSS rules in the app's stylesheet. Every Anvil app has a stylesheet named `theme.css` associated with it, which can be found in the App browser under "Assets". 

Because we created an Anvil app with the Material Design theme, our app's stylesheet is already populated with CSS rules. Let's open `theme.css` and modify some of the code.


![Location of `theme.css` in the App Browser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tte04xikvyfh8noe6g0.png)

Let's find the CSS code related to styling Buttons. `Ctrl + F` and search for "button". This should land us around line 548. Here we can see some CSS that is applied to components with the `btn` class. If we run our app and inspect the button again, we can see that it has a class called `btn`. In this rule, let's adjust the `background-color` to be something different:

```css
.btn, .btn-default, .file-loader>label {
  border-radius: 2px;
  font-size: 14px;
  ...
  background-color: lightblue; /* This line is changed */
  ...
}
```

Now, if we run the app, we can see that nothing has changed. Let's inspect the button to see what is going on. We can see the `background-color` we added in `theme.css` is crossed out, and instead the `background-color` that we added in the Properties Panel is taking precedence. 


![Code showing that the `background-color: gray` property in the `style` attribute is taking precedence.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tps3iqbs7weixd8c48n6.png)

When CSS properties conflict with each other, CSS has rules to determine which property is applied. Styling rules written in the stylesheet will be applied first, then rules written in the HTML will be applied. This is why our Button is `gray` and not `lightblue`. The `background-color: gray` property written in the HTML will be applied last and therefore overrides the `background-color: lightblue` property in `theme.css`.

If CSS styling rules written in the stylesheet conflict, then the last rule will override preceding rules. This is why stylesheets are **cascading**. For example, if we had the following code in a stylesheet (and no conflicting styling rules added to the HTML), then buttons would end up having a pink background:

```css
button {
  background-color: gray;
}

button {
  background-color: pink;
}
```

However, if rules have different selectors but could still conflict, then the most specific rule applies. Class selectors are more specific than type selectors. So in the following code, buttons with the `submit` class would have a gray background color despite the rule coming first:

```css
.submit {
  background-color: gray;
}

button {
  background-color: pink;
}
```

The cascade and specificity rules can be overridden by using `!important`. `!important` is applied to a property within a rule in order to make its value more important than any other conflicting value, but this is almost always a bad idea. We'll discuss why `!important` should be avoided, but let's first see how it works by making the `background-color` property we set in `theme.css` `!important`:

```css
.btn, .btn-default, .file-loader>label {
  border-radius: 2px;
  font-size: 14px;
  ...
  background-color: lightblue !important;
  ...
}
```

If we run the app again, the button now has a light blue background. Inspecting the button shows that the `background-color` set in the style attribute is crossed out this time. In practice, we should not use `!important` here. Instead, we should either set the `background-color` we want from the Properties Panel or remove the `background-color` set there and set it in `theme.css` without making it `!important`.


![The `background-color: lightblue` property is now `!important`, so the Button is light blue.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwr7wpdae76edrqet7rs.png)


_In general, **using `!important` should be avoided.** Occasionally, you may need to use it to override default styling rules that you don't have access to. (The example above is not one of these scenarios.) But overriding the cascade makes debugging difficult and will often cause other developers (and your future self) pain and confusion. Instead, try reordering rules and using more specific selectors. You can read more about specificity and `!important` [here](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity)._



### Anvil Roles

We can add CSS classes to Anvil components using Anvil [Roles](https://anvil.works/beta-docs/client/themes-and-styling/roles?utm_source=dev_to_css_guide). After you create a Role, you can write CSS rules in the app's stylesheet to define how the Role will affect components. You can apply the Role to a component through the Properties Panel or in code. 

Let's create a new Role in our app to apply to our Button. In the sidebar, click on "Theme", then choose "Roles". Click on "+ Add a new role" then choose a name for the role. I've named my role `submit` and have restricted it so that it can only be applied to Button components. 

![Creating a new Anvil Role called `submit` and restrict it to Button components.](https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/using-css/create-new-role.gif)

Let's now switch back to `Form1` and give the Button the `submit` Role. Let's also remove any properties we set in the Editor or in the Form code. 

![Giving the button the `submit` role.](https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/using-css/add-role.gif)

We should also change the code we altered in `theme.css`. Right now, all buttons in our app will be light blue, but let's use the role we just defined to only make Buttons with the `submit` Role light blue. So the code we changed in `theme.css` should look like this again:

```css
.btn, .btn-default, .file-loader>label {
  border-radius: 2px;
  font-size: 14px;
  ...
  background-color: transparent; /* this line is changed back */
  ...
}
```

The Button now has the `submit` Role, which means Anvil will give the component a CSS class. The class name will be the Role name with the prefix `anvil-role-`. We can now go into `theme.css` and write some styling rules for the `anvil-role-submit` class.

At the very bottom of `theme.css`, let's select the `anvil-role-submit` class and change the background color, the font color and the font size:

```css
.anvil-role-submit {
  background-color: lightblue;
  color: white;
  font-size: 22px;
}
```

Run the app to see how the code worked. 

Our button doesn't quite look right, so we should inspect the app to see what is going on. If we select the element with the light blue background, we can see that it is a `<div>` that has the `anvil-role-submit` class. Inside of this `<div>` is the Button we actually want to target. 


![Screenshot of the dev tools showing the HTML for the outer <div> element and the <button> nested inside](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x63h8kk9mwnt9t0b77ag.png)

Let's go back to `theme.css` and modify the selector so we select the `<button>` nested inside the `<div>`.

There are a few ways we can do this, but let's be as specific as possible and select `<button>` elements that have the `btn` class that are children of the `.anvil-role-submit` class:

```css
.anvil-role-submit > button.btn {
  background-color: lightblue;
  color: white;
  font-size: 22px;
}
```

Now let's rerun our app to see if we've selected the correct element.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/21c7ib5cebs3uhxn4692.png)

Great, it worked! 

---

## Summary 

In this guide, we have gone over the basics of using CSS in Anvil apps. We briefly covered [HTML and how it relates to CSS](#html-and-css). We also looked at [how to write CSS rules](#css-syntax) using [selectors](#selectors-and-classes) and [properties](#css-properties). We've also seen how we can use the [browser's developer tools](#using-the-developer-tools) to inspect code and make local changes. When [using CSS in Anvil](#using-css-in-anvil), we can edit the properties of Anvil components [with Python](#applying-css-via-python) or by [writing CSS rules in the app's stylesheet](#writing-css-in-the-stylesheet). We can also [define Anvil roles](#anvil-roles) to add CSS classes to Anvil components.


CSS is a very powerful tool, but we've only scratched the surface on what it can do. I highly recommend playing around with your browser's developer tools to inspect web pages and make local changes to the code. This is a great way to learn more about how CSS works. 

If you'd like to learn more about how to use CSS, check out my suggested resources below:

## Further reading

* For a short tutorial to help you **get started with CSS**, check out [MDN's CSS basics](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/CSS_basics).

* For an **introduction to HTML**, MDN have a [good, easy-to-follow tutorial](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML) designed for beginners.

* For a more **in depth introduction to CSS**, MDN also have a [good CSS tutorial](https://developer.mozilla.org/en-US/docs/Learn/CSS) that assumes no prior CSS knowledge but assumes you have completed their HTML tutorial.

* For a **full list of CSS properties** and examples of their use, check out the [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Properties_Reference).

* If you prefer more **interactive tutorials**, I highly recommend [Scrimba](https://scrimba.com/). Their [HTML and CSS crash course](https://scrimba.com/learn/htmlcss) is designed for beginners.

* For **articles on CSS topics** and cool tricks, see [CSS Tricks](https://css-tricks.com/).