One place for hosting & domains

      How To Use Opacity and Transparency to Create a Modal in CSS


      The author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      When styling HTML with CSS, there are multiple ways to adjust the opacity of elements, and multiple reasons to employ this effect in a design. Opacity can help soften a shadow, de-emphasize non-essential content during a specific task, or fade content in or out of view. You can accomplish these effects with the opacity property, the transparent color name, or alpha channels, which are an extension of color values with an additional segment for controlling opacity.

      Throughout this tutorial, you will use various ways to apply opacity and extra properties to effectively accomplish certain effects. You will create a modal that appears with a no-JavaScript approach using the :target pseudo class and the opacity, pointer-events, and transition properties. Then you will use each of the alpha channel color values to create shadow, border, and content overlays. You will also use the transparent color value to help make a gradient animate colors on a :hover event.

      Prerequisites

      • An understanding of CSS’s cascade and specificity features, which you can get by reading How To Apply CSS Styles to HTML with Cascade and Specificity.
      • Knowledge of type selectors, combinator selectors, and selector groups, which you can find in How To Select HTML Elements to Style with CSS.
      • An understanding of color properties. See How To Use Color Values with CSS to learn more about working with color in CSS.
      • Knowledge of CSS gradients with the background properties. Check out How To Apply Background Styles to HTML Elements with CSS to gain experience creating gradient backgrounds.
      • Experience with the box-shadow property, which you can learn more about in How To Style the Edges of HTML Elements with Borders, Shadows, and Outlines in CSS.
      • An empty HTML file saved on your local machine as index.html that you can access from your text editor and web browser of choice. To get started, check out our How To Set Up Your HTML Project tutorial, and follow How To Use and Understand HTML Elements for instructions on how to view your HTML in your browser. If you’re new to HTML, try out the whole How To Build a Website in HTML series.

      Setting Up the Base HTML and CSS

      In this first section, you will set up the HTML for the visual styles you will write throughout the tutorial. You will also create your styles.css file and add styles that set the layout of the content.

      To begin, open the index.html file in your text editor. Then, add the following HTML to the file:

      index.html

      <!doctype html>
      <html>
        <head>
          <meta charset="utf-8" />
          <title>Destination: Moon</title>
          <link rel="preconnect" href="https://fonts.googleapis.com"> 
          <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 
          <link href="https://fonts.googleapis.com/css2?family=MuseoModerno:wght@400;700&display=swap" rel="stylesheet">
          <link href="styles.css" rel="stylesheet" />
        </head>
        <body>
        </body>
      </html>
      

      Several page settings are defined inside the <head> element of the HTML. The <meta> element defines the character set to use for the text, which tells the browser how to interpret special characters in the code without using HTML character codes. The <title> element provides the browser with the title of the page. The <link> elements load in the page styles. The first three load in the font, Museo Moderno, from Google Fonts, and the last one loads the styles you will add to styles.css.

      Next, the page will need content to style. You will use sample content from Sagan Ipsum as filler copy to use with the styles. You will also apply HTML for a site header, containing the site name and a small navigation bar. Return to index.html in your text editor and add the highlighted HTML from the following code block:

      index.html

      <!doctype html>
      <html>
        <head>
          ...
        </head>
        <body>
          <header class="site-header">
            <h1 class="site-name">Destination: <strong>Moon</strong></h1>
            <nav>
              <ul class="nav-list">
                <li><a href="#" class="nav-link">Base Station</a></li>
                <li><a href="#" class="nav-link">Travel Packages</a></li>
                <li><a href="#" class="nav-link">Accommodations</a></li>
                <li><a href="#" class="nav-link">Plan Your Trip</a></li>
            </ul>
            </nav>
          </header>
          <main>
            <section>
              <h2>Schedule Your Trip</h2>
              <p>Sea of Tranquility great turbulent clouds with pretty stories for which there's little good evidence extraordinary claims require extraordinary evidence. Citizens of distant epochs rings of Uranus intelligent beings birth take root and flourish across the centuries. Corpus callosum invent the universe as a patch of light the only home we've ever known a mote of dust suspended in a sunbeam made in the interiors of collapsing stars. Kindling the energy hidden in matter Orion's sword.</p>
              <p>Vastness is bearable only through love emerged into consciousness not a sunrise but a galaxyrise emerged into consciousness courage of our questions across the centuries and billions upon billions upon billions upon billions upon billions upon billions upon billions.</p>
                <a href="#" class="button">Read the Disclaimer!</a>
            </section>
          </main>
        </body>
      </html>
      

      Be sure to save your index.html file and leave it open in your text editor. Next, create a new file called styles.css and open it in the text editor. This is the file that is referenced in the <head> element of index.html. In the styles.css file, add the following code:

      styles.css

      body {
        margin: 0;
        font: 100%/1.5 sans-serif;
      }
      
      main {
        margin: 6rem auto;
        width: 75ch;
        font-size: 1.125rem;
      }
      
      h2 {
        font: 400 1.875rem/1.25 MuseoModerno, sans-serif;
        color: #6b2d6b;
      }
      
      .site-header {
        font: 1.125rem / 1.25 MuseoModerno, sans-serif;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 2rem;
        color: white;
        background: linear-gradient(135deg, #8e3d8e, #230f23);
      }
      
      .site-name {
        margin: 0;
        font-size: 1.75rem;
        font-weight: 400;
      }
      
      .nav-list {
        margin: 0;
        padding: 0;
        list-style: none;
        display: flex;
        align-items: stretch;
      }
      
      .nav-link {
        color: inherit;
        display: block;
        text-decoration: none;
        padding: 1.25rem 1.5rem;
      }
      
      .nav-link:hover,
      .nav-link:focus {
        color: #230f23;
        background-color: white;
      }
      
      .button {
        text-decoration: none;
        display: inline-block;
        padding: 0.5rem 1.25rem;
        color: white;
        background: #4c90b2;
        border: 1px solid #2d566b;
        border-radius: 0.5rem;
      }
      
      .button:hover,
      .button:focus {
        background-color: #2d566b;
      }
      

      These styles set up the general aesthetic and layout of the page, with the styles applied to the body and main elements. The .site-header, .site-name, .nav-list, and .nav-link selectors all define the styles on the page header. The .button and .button:hover rules change an <a> element to appear like a large, clickable button.

      Save your changes to styles.css, then open a web browser. Select the File menu item and then select the Open option. Next, navigate to your project folder and load your index.html file in the browser. The following image demonstrates how the page will render in the browser:

      Sample website with a purple nav bar, a centered block of copy text, and a blue button with the words

      The CSS you have written so far creates a purple header at the top of the page with a site title and navigation in white text. Below, the content consists of a purple heading and two paragraphs of text. The width of the content is constrained to 75 characters with the max-width: 76ch property value on the main element selector. Lastly, the blue button with the text Read the Disclaimer! is a large, interactive element below the content.

      Throughout this section you set up your HTML in the index.html file and created the base styles in the styles.css file. In the next section, you will use the opacity property to cause a new element to disappear and reappear with the :target pseudo class.

      Creating :target State with opacity to Show and Hide Elements

      A useful application of the opacity property is to cause content to fade in and out on the screen. One instance of such an effect is when a modal, a UI element (also known as a light box) that appears in front of the rest of your page’s content, is transitioned into view. You can create this effect with a combination of the opacity and pointer-events properties and the :target pseudo-class.

      Start by opening index.html to create the contents of the modal. Add the highlighted HTML from the following code block between the </section> and </main> closing tags:

      index.html

      <!doctype html>
      <html>
        <head>
          ...
        </head>
        <body>
          ...
          <main>
            <section>
              ...
            </section>
            <div class="modal-container">
              <section class="modal">
                <header class="modal-header">
                  <h2 class="modal-title">Destination: Moon Disclaimer</h2>
                  <a href="#" class="modal-close">Close</a>
                </header>
                <div class="modal-content">
                  <p><strong>Disclaimer:</strong> Vastness is bearable only through love emerged into consciousness not a sunrise but a galaxyrise emerged into consciousness courage of our questions across the centuries and billions upon billions upon billions upon billions upon billions upon billions upon billions.</p>
                </div>
              </section>
            </div>
          </main>
        </body>
      </html>
      

      Save your changes to index.html, then return to styles.css in your text editor and append the highlighted CSS in the following code block to your file:

      styles.css

      ...
      
      .button:hover {
        background-color: #2d566b;
      }
      
      .modal-container {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 1000;
        background-color: black;
        display: flex;
      }
      
      .modal {
        margin: auto;
        width: 90%;
        max-width: 40rem;
        background-color: white;
        border-radius: 1.5rem;
      }
      
      .modal-header,
      .modal-content {
        padding: 1.5rem;
      }
      

      The .modal-container class defines an area that will cover the full visible space with a fixed element. Then the display: flex on the .modal-container combined with the margin: auto on the .modal selector will center the content to the page both vertically and horizontally.

      Save your changes to styles.css and return to you browser to refresh index.html. The page’s contents are no longer visible as a black overlay has taken over the page with a white container, as rendered in the following image:

      White modal box with a black background covering the rest of the page

      Now that the modal is in place and covering the contents of the page, it needs to be hidden until instantiated. The opacity property is an older property that allows translucency to be placed on an element and its contents. The value of the opacity property can range from 0 to 1, with any decimal point between.

      To begin using the opacity property, return to styles.css in your text editor. On the .modal class selector, add an opacity property with a value of 0, as highlighted in the following code block:

      styles.css

      ...
      .modal-container {
         position: fixed;
         top: 0;
         right: 0;
         bottom: 0;
         left: 0;
         z-index: 1000;
         background-color: black;
         display: flex;
        opacity: 0;
      }
      ...
      

      This will cause the entire modal view to be visually hidden on the screen. The modal should only be visible when it needs to be. To achieve this conditional appearance, you can use the :target pseudo-class.

      After the .modal-container selector, add a new selector for .modal-container:target. Inside the selector block, set another opacity property to a value of 1. The highlighted CSS in the following code block shows how this is formatted:

      styles.css

      ...
      .modal-container {
        ...
        opacity: 0;
      }
      
      .modal-container:target {
        opacity: 1;
      }
      ...
      

      Save these changes to styles.css.

      The :target is instantiated when an element has a URL focus. In web browsers, the id attribute on an HTML element can be referenced in the URL as denoted by the pound or hash symbol (#). In order for the .modal-container:target to activate, the same element needs an id element, and the page needs a way to trigger that URL.

      Return to index.html in your text editor. On the <div class="modal-container"> element, add an id attribute set to the value disclaimer. Then, on the <a href="#" class="button"> element, change the href value from # to #disclaimer. Reference the highlighted HTML in the following code block for how this is written:

      index.html

      <!doctype html>
      <html>
        <head>
          ...
        </head>
        <body>
          ...
          <main>
            <section>
               ...
               <a href="https://www.digitalocean.com/community/tutorials/#disclaimer" class="button">Read the Disclaimer!</a>
             </section>
             <div id="disclaimer" class="modal-container">
               ...
             </div>
          </main>
        </body>
      </html>
      

      The change to the href value tells the browser to go to the element with the id value of disclaimer of the current page. Once the #disclaimer is added to the URL, then the :target in the CSS will activate.

      Save these changes to index.html, then return to styles.css.

      The way the page is structured now, the modal will capture all click and touch events coming from a mouse or touchscreen interaction. This is because, though completely transparent, the modal element is still covering the whole page. In order to remove interactivity from the element, you’ll add a pointer-events property with a value of none to the .modal-container selector. Then, once the modal is visible, it will need to be able to receive interaction events again. On the :target pseudo-class add pointer-events set to all, as highlighted in the following code block:

      styles.css

      ...
      .modal-container {
        ...
        opacity: 0;
        pointer-events: none;
      }
      
      .modal-container:target {
        opacity: 1;
        pointer-events: all;
      }
      ...
      

      The pointer-events property changes how an element interacts with a mouse or touch-based input device. By setting the value to none, the element becomes invisible not only to sighted users, but to pointer-based input devices as well. Then, the all value reinstates the interaction, but only when the .modal-container is specified in the URL to be active and visible.

      Lastly, to cause the modal to fade in and out of view, you’ll add a transition property to animate between 0 and 1 values for opacity.

      Return to styles.css and add a transition property to the .modal-container selector, as highlighted in the following code block:

      styles.css

      ...
      .modal-container {
        ...
        opacity: 0;
        pointer-events: none;
        transition: opacity 250ms ease;
      }
      
      .modal-container:target {
        opacity: 1;
        pointer-events: all;
      }
      ...
      

      The transition property is shorthand for a series of properties. The opacity tells the browser that this is the property to transition between. The 250ms is the time the transition should take to complete, with the unit standing for milliseconds. Finally, the ease describes how the transition will occur. In this case, ease means it will start slow, speed up, and then slow down again near the end of the transition.

      The transition will work when the modal appears and disappears by pressing the Close link inside the modal. This Close link has an href value set to #, which will change the URL from #disclaimer to #, removing the :target state.

      Save your changes to styles.css and refresh index.html in the browser. The following animation illustrates how the modal will appear and disappear:

      Animation of the modal appearing in a smooth transition, then disappearing with a smooth transition.

      This section introduced you to the opacity property, which you used to visually hide a modal container. You also used the :target pseudo-class, pointer-events property, and transition property to create a fade-in and fade-out effect. In the next section, you will use colors with alpha channels to make the modal more translucent.

      Using Alpha Channels to Create Transparent Color Values

      An alpha channel is like the opacity property, but instead is an additional segment for a color value defined via rgb(), hsl(), or hexadecimal. Where the opacity property adjusts the whole element and its children, the alpha channel only adjust the opacity of the color on a given property. Throughout this section, you will use each of the alpha channel color values and put them into practice.

      To begin working with alpha channel color values, open stlyes.css in your text editor. Then go to the .modal-container class selector. Change the background-color property’s value from #000 to rgba(0, 0, 0, 0.75), as highlighted in the following code block:

      styles.css

      ...
      .modal-container {
        ...
        background-color: rgba(0,0,0,0.75);
        ...
      }
      ...
      

      The rgba() color value works like the rgb(), containing three comma-separated numbers that indicate a level of red, green, and blue light. When one of the color values is set to 0, it is completely off (black), and 255 means it is at full brightness (white). Between these three color channels, millions of colors can be produced. The fourth number is the alpha channel, which works like the opacity property and is a decimal point value from 0 to 1. An adjustment to the alpha channel causes the color to become transparent, allowing the content behind it to become visible through the color.

      Save your changes to styles.css and open index.html in a web browser. Press the Read the Disclaimer! button so the modal activates. The black overlay background is still black, but is now also transparent, revealing the page behind it:

      The disclaimer modal, with the rest of the page visible behind a translucent black background.

      Now that the overlay is transparent, turn to the modal and give it more visual styling by changing the background to a purple gradient with white text. Return to styles.css in your text editor and add the following highlighted CSS from the next code block:

      styles.css

      ...
      .modal {
        margin: auto;
        width: 90%;
        max-width: 40rem;
        background: linear-gradient(135deg, hsl(300, 40%, 20%),hsl(300, 40%, 5%));
        border-radius: 1.5rem;
      }
      
      .modal-header,
      .modal-content {
        padding: 1.5rem;
      }
      
      .modal-header {
        display: flex;
        justify-content: space-between;
      }
      
      .modal-title {
        margin: 0;
        color: white;
      }
      
      .modal-close {
        color: white;
      }
      
      .modal-content {
        color: white;
      }
      
      

      Save this update to styles.css, then refresh index.html in your browser. The style of the modal will update and render as illustrated in the following image:

      The modal with a gradient background between purple and black and white lettering.

      Now, return to styles.css in your text editor. You will now use the hsla() color value to lighten the color of the modal header. You will also need to set the top corners to have a border-radius value that matches the modal, so the header doesn’t appear outside the modal area. The highlighted CSS in the following code block demonstrate how to set this up:

      styles.css

      ...
      .modal-header {
        display: flex;
        justify-content: space-between;
        background-color: hsla(300, 80%, 90%, 0.2);
        border-radius: 1.5rem 1.5rem 0 0;
      }
      ...
      

      The background-color value uses the hsla() format, and like the rgba() value, it is the hsl() format but with an alpha channel. The hsl() consists of three parts: a degree value from the color wheel, a saturation percent value, and a lightness percent value, which generates a final color. The 300 places the color value between blue and red on the color wheel, the 80% is a heavy saturation meaning more color and less gray, and the 90% lightens the final color. Lastly, the alpha channel works the same as the opacity property, and 0.2 sets the value closer to fully transparent. This will create a lightened overlay on top of the gradient, providing definition to the header.

      Save these changes to styles.css and return to the browser to refresh index.html. The header of the modal now has a pinker highlight to the area, distinguishing it from the content of the modal. The following image shows how the modal header is now rendered in the browser:

      Modal with header brightened to distinguish it from the modal content.

      Another way to create transparent color values is with hexadecimal values. Hexadecimal color values consist of three pairs of a combination of 0 to 9 or a to f and equate to a number ranging from 0 to 255. The first three digits are a red, green, and blue value, formatted as #RRGGBB. To create an alpha channel, a fourth set is added, making the pattern #RRGGBBAA.

      To begin working with hexadecimal alpha channels, return to styles.css in your text editor. You will now add a border to the modal’s header and content areas to give it more definition. These borders will use the same hexadecimal value, but will be given different values for the alpha channel. The highlighted CSS from the following code block shows how to write these styles:

      styles.css

      ...
      .modal-header {
        display: flex;
        justify-content: space-between;
        background-color: hsla(300, 80%, 90%, 0.2);
        border-radius: 1.5rem 1.5rem 0 0;
        border: 4px solid #f7baf72f;
        border-bottom: none;
      }
      ...
      .modal-content {
        color: white;
        border-radius: 0 0 1.5rem 1.5rem;
        border: 4px solid #f7baf744;
        border-top: none;
      }
      ...
      

      The header and the content each have the same hexadecimal color with #f7baf7, but they have different alpha channel values. The modal-header selector’s border-color has an alpha channel set to 2f, which is more transparent, since 00 is a fully transparent alpha channel value. The .modal-content has its alpha channel set to 44, which makes it more opaque.

      Save your changes to styles.css and refresh index.html in the web browser. The following image illustrates how these borders are rendered in the browser:

      Modal with added border around the modal container, rendered by adding transparency.

      Lastly, a six-digit hexadecimal color can be written as a three digit shorthand, where #33ccee is the same as #3ce. Likewise, a hexadecimal value with an alpha channel can be written as a four digit shorthand so that #33ccee99 can be shortened to #3ce9 and be the same color.

      To begin working with a shorthand hexadecimal with alpha channel, return to stlyes.css in your text editor. Then, go to the .modal class selector and add a box-shadow property. Here you will create a large drop shadow on the modal, which will be black but softened by an alpha channel. Add the highlighted CSS in the following code block to your .modal selector block:

      styles.css

      ...
      .modal {
        margin: auto;
        width: 90%;
        max-width: 40rem;
        background: linear-gradient(135deg, hsl(300, 40%, 20%),hsl(300, 40%, 5%));
        border-radius: 1.5rem;
        box-shadow: 0 1rem 2rem #000a;
      }
      ...
      

      This shadow drops down the x-axis by 1rem and spreads out the blur 2rem. Next, the #000a value defines a full black color by turning off all three color values. The a, which is equivalent to aa and has a numerical value of 170, provides the alpha channel with approximately a 66% transparency. This dims the shadow slightly but keeps it substantial enough to provide depth below the modal.

      Be sure to save this addition to styles.css, then refresh index.html in the browser. The modal now has much more definition and depth. The following image provides a rendering of the modal with the various color values:

      Modal with added shadow to make it look like it is floating above the page content.

      In this section, you used the three different color values with alpha channels to apply opacity to colors on specific properties. You added these colors to background-color properties, border properties, and a box-shadow property. In the next section, you will use the named color value of transparent to create unique gradients and hide content.

      Adding the transparent Color Value to a linear-gradient

      The various color values that support alpha channels are helpful for when a color still needs to be identifiable. However, when no color is needed, the transparent named color becomes useful. In this section, you will hide the Close button in the modal and create an X shape with a linear-gradient(), all with the use of the transparent value.

      To start using the transparent value, open styles.css in your text editor. Then, go to the .modal-close class selector that you added earlier. Inside the selector, change the color property value from white to transparent, as highlighted in the following code block:

      styles.css

      ...
      .modal-close {
        color: transparent;
      }
      ...
      

      This change will not remove the text from the space; it will only remove it from visually rendering on the page.

      Next, you will create a square out of the close link so there is a place to create the X shape. Start by adding a display property set to block, which allows the <a> to be more visually configurable. Next, create a height and width property and set each to 1.5rem, which creates the square shape. Finally, add an overflow property set to hidden, which will prevent text from going outside the container and adding interactive space. The highlighted CSS from the following code block shows how to set up the square:

      styles.css

      ...
      .modal-close {
        color: transparent;
        display: block;
        height: 1.5rem;
        width: 1.5rem;
        overflow: hidden;
      }
      ...
      

      The last part is to create the X shape with a multiple-background instance consisting of two linear-gradient() values. To set this up, add the highlighted code from the following code block:

      styles.css

      ...
      .modal-close {
        color: transparent;
        display: block;
        height: 1.5rem;
        width: 1.5rem;
        overflow: hidden;
        background-image:
          linear-gradient(
            to top right,
            transparent 48%,
            white 48%,
            white 52%,
            transparent 52%
          ),
          linear-gradient(
            to top left,
            transparent 48%,
            white 48%,
            white 52%,
            transparent 52%
          );
      }
      ...
      

      The first thing to note about this code is that the different segments of the linear-gradient() are on separate lines, which is done to help make the complex background more comprehensible and legible. This CSS is still valid, and it is not required that values are on the same line as the property. Next, the duplicated percent values for transparent and white mean there will be no gradation. Instead the color will flip immediately from transparent to white. Lastly, the to the right and to the top makes two gradients on 45 degree angles that overlap.

      Save this change to styles.css and open index.html in a web browser. Select the Read the Disclaimer! button and the modal will now have a large, thin X shape instead of a close link, as rendered in the following image:

      Modal box with the 'Close' button replaced with a thin white X.

      Lastly, a :hover and :focus state is needed to help make the X shape more noticeable when it is the center of interaction. For this, you will duplicate the previous gradients and adjust the position to grow the solid white area.

      To create an interactive state for the X, return to styles.css in your text editor. Following the .modal-close class selector, create a new group selector consisting of .modal-close:hover and .modal-close:focus. Then, duplicate the background-image property and value from .modal-close into the new selector. Lastly, decrease the 48% segments to 46% and increase the 52% to 54%.

      style.css

      ...
      .modal-close {
        ...
      }
      
      .modal-close:hover,
      .modal-close:focus {
        background-image:
          linear-gradient(
            to top right,
            transparent 46%,
            white 46%,
            white 54%,
            transparent 54%
          ),
          linear-gradient(
            to top left,
            transparent 46%,
            white 46%,
            white 54%,
            transparent 54%
          );
      }
      ...
      

      Save these changes to styles.css and refresh the page in your browser. Now, as the X is hovered over or given keyboard focus, the size of the gradients creating the shape will increase, giving an effect as though the X is bolded. The following animation demonstrates how this effect is rendered in a browser during a hover event:

      Animation of the cursor hovering over the X button. The lines of the X become visibly wider.

      This section introduced you to the transparent property, and you used it to hide content and create an X icon using linear-gradient() values. In the last section, you will use the transparent value on a gradient to help provide an animation effect on a button-styled element.

      Using the :hover State to Transition Between Transparent color Values

      One aspect of the transition property that sometimes requires creative solutions is that not all properties can be animated. One of these properties is the background-image, meaning the values of a linear-gradient on this property cannot animate. However, the background-color value can animate even if a background-image is present. In this section, you will create a transition animation that appears to be a gradient animation with the use of transparent and alpha channel color values.

      To create an animated gradient, open styles.css in your text editor. Then go to the .button class selector. The .button class already has a change in the background-color between its selector and the .button:hover. Add the highlighted transition property and value from the following code block to your styles.css file:

      styles.css

      ...
      .button { 
        text-decoration: none;
        display: inline-block;
        padding: 0.5rem 1.25rem;
        color: white;
        background: #4c90b2;
        border: 1px solid #2d566b;
        border-radius: 0.5rem;
        transition: background-color 250ms ease;
      }
      
      .button:hover,
      .button:focus {
        background-color: #2d566b;
      }
      ...
      

      Save your changes to styles.css and open index.html in you web browser. Hovering the button with a cursor will now cause the background-color to animate between light blue and dark blue. The following animation shows how this is rendered in the browser:

      An animation of the cursor hovering over the

      Now, to add the gradient, go back to styles.css in your text editor. Return to the .button selector and add a background-image property with a linear-gradient(). The direction of the gradient will be to bottom and will start with an alpha channel light blue then go to transparent. The animation will end with an alpha channel dark blue. The highlighted CSS in the following code block demonstrates how to write this gradient:

      styles.css

      ...
      .button { 
        text-decoration: none;
        display: inline-block;
        padding: 0.5rem 1.25rem;
        color: white;
        background: #4c90b2;
        border: 1px solid #2d566b;
        border-radius: 0.5rem;
        background-image:
          linear-gradient(
            to bottom,
            hsla(200, 40%, 80%, 0.4),
            transparent,
            hsla(200, 40%, 20%, 0.6)
          );
        transition: background-color 250ms ease;
      }
      ...
      

      This gradient overlays the background-color, giving the appearance that the gradient is passing from a light blue to a middle blue and then a dark blue. When the button encounters an interactive event, the background-color changes to a darker blue, creating an illusion that the overall gradient darkened.

      Save these updates to styles.css and then return to your index.html file in the browser and refresh the page. As shown in the following animation, as the cursor hovers the button the gradient appears to animate from a light blue gradient to a dark blue gradient:

      An animation of the cursor hovering over the

      In this last section, you used color values, the transparent named value, and the transition property to create an illusion of a gradient animating. Due to this, you also learned what kinds of properties can be animated.

      Conclusion

      Throughout this tutorial, you used the opacity property and many color values with alpha channels. You used opacity with pointer-events and transition to create a fade-in effect to display a modal on demand. You also used the various color values available to control the transparency and overlay of color on the content. You used the transparent named value to create an X icon to close the modal. Finally, you used a combination of colors, transparent value, gradients, and transition to create the illusion of an animated gradient on a button.

      There are many useful reasons to employ opacity and transparent colors to a web design. The opacity property can be used to animate a fade-in and fade-out effect on elements that are meant to be visible when needed. The various color values that allow for transparency control provide many ways to blend colors and content together. Altogether, these methods of creating transparency can create many unique effects and styles.

      If you would like to read more CSS tutorials, try out the other tutorials in the How To Style HTML with CSS series.



      Source link

      How To Style HTML Elements with Borders, Shadows, and Outlines in CSS


      The author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Working with shadows, borders, and outlines is a key component of web development, and can provide visual definition around HTML elements and text items. The appearance of borders and shadows can be manipulated via five main CSS properties: border, border-radius, box-shadow, text-shadow, and outline. Shadows provide depth and help elements stand out, while the border properties can perform many different visual functions, from creating a linear divider between content to defining the space of a grid. The border-radius property creates rounded corners on boxes, and can even make a circular shape. Lastly, outline is an often overlooked property that provides much of the same functionality of the border property without disrupting the flow of content.

      In this tutorial, you will work with these properties to create a legality notice for a fictional space tourism company. Throughout the demo you will create visually rich containers by using edge-based properties. Additionally, you will take into account the nuances about more complex values, such a multiple shadows and how different browsers can implement certain properties differently.

      Prerequisites

      Setting Up the Base HTML and CSS

      In this section, you will set up the HTML base for all the visual styles you will write throughout the tutorial. You will also create your styles.css file and add styles that set the layout of the content.

      Start by opening index.html in your text editor. Then, add the following HTML to the file:

      index.html

      <!doctype html>
      <html>
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <title>Travel Disclosure - Destination: Moon</title>
          <link href="https://www.digitalocean.com/community/tutorials/styles.css" rel="stylesheet" />
        </head>
        <body>
        </body>
      </html>
      

      There are a lot of page settings defined inside the <head> element. The first <meta> element defines the character set to use for the text. This way most special characters, such as accent marks, will render without special HTML codes. The second <meta> element tells browsers, and mobile browsers in particular, how to treat the width of the content; otherwise, the browser will simulate a 960px desktop width. The <title> element provides the browser with the title of the page. The <link> element loads the CSS file in which you will write your styles throughout this tutorial.

      The page will also need content to style. For the legal text, you will use sample content from Legal Ipsum as filler copy, intended for styling purposes only.

      Return to index.html in your text editor and add the highlighted HTML from the following code block:

      index.html

      <!doctype html>
      <html>
        ...
        <body>
          <section class="disclosure-alert">
            <header class="disclosure-header">
              <h2  class="disclosure-title"><em>Destination: Moon</em> Travel Disclosure</h2>
            </header>
            <div class="disclosure-content">
              <p>Although space travel is routine practice, there are many unknown possibilities that any traveller must be aware of before traveling with <em>Destination: Moon</em>. Agreeing to this disclosure of knowns is required prior to purchase of tickets with <em>Destination: Moon</em>. PLEASE, READ AND AGREE TO THE FOLLOWING DISCLOSURE OF TRAVEL UNKNOWNS BEFORE PROCEEDING TO PURCHASE.</p>
              <div class="legal-contents">
                <p>Effect of Termination. Upon termination, You agree not to use it under the terms of Sections 4(a) through 4(e) for that Covered Code, or any third party. Description of Modifications.<p>
                <p>You must make sure that you know you can do these things. To make sure the requirements of this Agreement. REQUIREMENTS A Contributor may participate in any way. Notwithstanding the foregoing, if applicable law or agreed to in writing, the Copyright Holder, but only to the terms applicable to Covered Code. Inability to Comply Due to Statute or Regulation.</p>
                <p>If it is impossible for You to the Recipient retains any such Additional Terms. Versions of This License. If you are re-using, b) a hyperlink (where possible) or URL to the terms of Sections 4(a) through 4(e) for that Work shall terminate if it fails to comply with the exception of content that is granting the License. License Terms 1.</p>
                <p>Grant of Patent Infringement. If you have knowledge of patent infringement litigation, then the only applicable Base Interpreter is a "commercial item" as defined in 48 C.F.R. Consistent with 48 C.F.R.</p>
                <p>U.S. Government End Users acquire Covered Code (Original Code and/or as part of a Larger Work; and b) allow the Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Distributor in writing of such Contributor, if any, to grant more extensive warranty protection to some or all of these conditions: (a) You must make it clear that any Modifications made by such Respondent, or (ii) withdraw Your litigation claim is resolved (such as Wikimedia-internal copying), it is Recipient's responsibility to secure any other exploitation. Program, and in any of the provisions set forth in Section 4(b), you shall terminate if it fails to comply with.</p>
                <p>Please note that these licenses do allow commercial uses of your company or organization, to others outside of this License Agreement), provided that You meet the following terms which differ from this License) and (b) You must duplicate the notice in Exhibit A in each changed file stating how and when you changed the files and the definitions are repeated for your past or future use of the Original Code; or 3) for infringements caused by: i) third party against the drafter will not be used as a handle): 1895.22/1011. This Agreement shall be held by the terms of this agreement. If any provision of this license which gives you legal permission to modify NetHack, or otherwise using this software in source and binary forms, with or without modification in printed materials or in related documentation, stating that you provide a service, including but not limited to the terms under which you distribute, wherever you describe the origin or ownership of such termination, the Recipient a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6b1 or any part of Derivative Works. If You initiate litigation by asserting a patent infringement against You in that instance.</p>
                <p>Effect of New York and the like. While this license document the following disclaimer in the Work contain all the conditions listed in Clause 6 above, concerning changes from the Work. If you created a Modification, you may at your option offer warranty protection to some or all of the Licensed Program as a product of your Modifications available to others outside of this License.</p>
                <p>Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted to Licensor for inclusion in the documentation and/or other rights consistent with this program; if not, write to the modified files to carry prominent notices stating that You distribute, all copyright, patent, trademark, and attribution notices from the Public Domain or from the Original Code; 2) separate from the Public Domain or from the Work, you may distribute a Compiled Work on their system exactly as it is being maintained, then ask the Current Maintainer to update their communication data within one month. If the program is free software; you can change the License will not have to defend and indemnify every other Contributor to control, and cooperate with the Source Code version of the Licensed Program, or any Contributor.</p>
              </div>
              <div class="button-group">
                <a href="#" class="button button-primary">
                  Agree
                </a>
                <a href="#" class="button button-secondary">
                  Disagree
                </a>
              </div>
            </div>
          </section>
        </body>
      </html>
      

      Save your changes to index.html and then open your web browser. Select the File menu item and then select the Open option and load your index.html file in the browser. The following image demonstrates how this HTML will render in the browser:

      Several paragraphs of content in black serif text on a white background, with a larger bold headline above and two blue text links below.

      Make a new file called styles.css in the same directory as index.html, then open it in your text editor. This file will contain all the styles used throughout the tutorial. The first set of styles will apply a general aesthetic that you will build from. Apply the CSS from the following code block to your styles.css file:

      styles.css

      html, body {
        height: 100%;
      }
      
      body {
        display: flex;
        margin: 0;
        font: 100% / 1.5 sans-serif;
        background: url("images/moon-bg.jpg") no-repeat fixed center / cover black;
      }
      .disclosure-alert {
        background-color: hsl(0, 0%, 95%);
        width: 85%;
        max-width: 48rem;
        margin: auto;
        color: hsl(0, 0%, 20%);
      }
      .disclosure-header {
        background: linear-gradient(hsl(300, 50%, 20%), hsl(300, 50%, 10%));
        padding: 2rem 0.5rem;
        text-align: center;
        color: hsl(300, 50%, 95%);
      }
      .disclosure-title {
        margin: 0;
        font-size: 2rem;
        line-height: 1.25;
      }
      .disclosure-content {
        margin: 1.5rem;
      }
      .legal-contents {
        margin-top: 1.5rem;
        background-color: white;
        padding: 0.75rem;
        font-family: "Times New Roman", serif;
      }
      .button-group {
        margin-top: 1.5rem;
        display: flex;
        justify-content: center;
      }
      .button {
        display: inline-block;
        text-align: center;
        padding: 0.5rem 1rem;
        background: black;
        text-decoration: none;
        color: white;
        width: 50%;
        max-width: 8rem;
      }
      .button + .button {
        margin-left: 1.5rem;
      }
      .button-primary {
        background: linear-gradient(to bottom, hsl(200, 100%, 30%), hsl(200, 100%, 20%));
      }
      .button-primary:hover {
        background: linear-gradient(to bottom, hsl(200, 100%, 25%), hsl(200, 100%, 15%));
      }
      .button-secondary {
        background: linear-gradient(to bottom, hsl(200, 10%, 30%), hsl(200, 10%, 20%));
      }
      .button-secondary:hover {
        background: linear-gradient(to bottom, hsl(200, 10%, 25%), hsl(200, 10%, 15%));
      }
      

      The styling in this file sets the initial layout of the page, with a centered legal disclosure, buttons with spacing and rendered with a linear gradient, and an image of the moon used as the background. Before continuing, be sure to save the styles.css file.

      In order to display the image linked in the background property of the body ruleset, you will need the Moon background image. First, make an images directory in the same folder as your index.html file:

      Use your browser to download this file to your newly created images directory, or use the following curl command to download it via the command line:

      • curl -sL https://assets.digitalocean.com/articles/68102/moon-bg.jpg -o images/moon-bg.jpg

      Next, return to and refresh your browser. The browser will now render and apply the styles to the content of the page. The following image shows how the full page is rendered:

      Large webpage showing multiple paragraphs inside a container with a purple bar at the top with light pink text with a blue and gray button at the bottom, in front of a close up photo of the moon.

      The length of the content makes for a very long page. Since this is intended as legal copy, the content of .legal-contents can become a scrollable space. This is done through a combination of the properties height, max-height, and overflow.

      To create a scrollable area, open styles.css in your text editor. Next, adjust the height of the legal content with the following code:

      styles.css

      ...
      .legal-contents {
        height: 50vh;
        max-height: 20rem;
        overflow: auto;
        margin-top: 1.5rem;
        background-color: white;
        padding: 0.75rem;
        font-family: "Times New Roman", serif;
      }
      ...
      

      In this code, you created a height property in the .legal-contents selector block, then set its value to 50vh, meaning 50% of the viewport window’s height. You also created a max-height property with its value set to 20rem. Lastly, you added an overflow property with a value of auto, which creates the scroll bar if the content overflows the container.

      Save these additions to your styles.css file, then return to your browser and refresh index.html. The full height of the page and main container has condensed. Now, the Legal Ipsum copy can be scrolled inside of its designated container, as illustrated in the following animation:

      Animation of paragraphs of text scrolling with in a smaller content area.

      Throughout this section, you set up the primary HTML that you will use for the remainder of the tutorial. You also set up a scrollable space with the overflow property. In the next section, you will work with the border property to apply a border to these containers.

      Using the border Property

      The border property is one of the original ways to apply styles on the edges of elements. It applies a line in any color to the outer perimeter of a container. The property’s value consists of three components: the thickness, the style, and the color. The border property applies these values to all four sides of an element. You can specify individual sides with the direction variations of border, such as the border-top property, which will apply only to the top of an element.

      To begin working with the border property, open styles.css in your text editor and go to the .disclosure-alert class selector. Within the selector block, add a border property with a value set to 1px solid hsl(0, 0%, 0%), as highlighted in the following code block:

      styles.css

      ...
      .disclosure-alert {
        background-color: hsl(0, 0%, 95%);
        width: 85%;
        max-width: 48rem;
        margin: auto;
        color: hsl(0, 0%, 20%);
        border: 1px solid hsl(0, 0%, 0%);
      }
      ...
      

      This border property is a shorthand property, meaning its value is a combination of other values. In this case, the thickness of 1px represents the border-width property value. This value can be any numerical value with a unit along with a few named values: thin, medium, and thick. Next, solid is the border-style value, which defines how the line around the element will appear, in this case as a solid, continuous line. Other values for border-style include dotted, dashed, double, and none. The final value defines the border-color property, which can be any valid color value.

      Save your changes to styles.css, then open index.html in a web browser. The primary content container will now have a thin black border around it, which is most evident as it overlays the moon background image. The following image depicts how the border appears on the main content area:

      Box of content with purple heading wrapped by a thin black border over a photo of the moon.

      Next, you can use the border property to create a sense of depth by applying highlights and shadows to an element. You can accomplish this by using a directional border on one side that is lighter than the background color, then a darker color on the adjacent side.

      Return to styles.css in your text editor, then go to the .disclosure-header class selector block. The linear-gradient() on the background property defines a dark purple gradient transitioning to a slightly darker shade. To create more depth than the gradient alone, adjust the border with the following code:

      styles.css

      ...
      .disclosure-header {
        background: linear-gradient(hsl(300, 50%, 20%), hsl(300, 50%, 10%));
        padding: 2rem 0.5rem;
        text-align: center;
        color: hsl(300, 50%, 95%);
        border-top: 1px solid hsl(300, 50%, 35%);
        border-bottom: 1px solid hsl(300, 50%, 5%);
      }
      ...
      

      You added a border-top property with a value of 1px solid hsl(300, 50%, 35%), which is a bit lighter than the starting gradient value. Next, you created a border-bottom property set to a value of 1px solid hsl(300, 50%, 5%), which is slightly darker than the end of the gradient.

      Save your changes to styles.css, then return to the browser and refresh index.html. The purple header background now has a slight highlight of purple running across the top of the header, and a slight shadow along the bottom. The following image shows how this will appear in the browser:

      A purple background header with a light purple thin border on the top and a dark purple thin border on the bottom.

      Since border is a shorthand property, you can add additional longhand properties. A border can be applied that defines the width and the style of the two button classes, while a border-color can be applied on the individual classes.

      To start working with border-color, open styles.css in your text editor. In the selector block for .button, add a border property with a value of 1px solid, then add a border-color property for .button-primary and .button-secondary:

      styles.css

      ...
      .button {
        ...
        border: 1px solid;
      }
      ...
      .button-primary {
        background: linear-gradient(to bottom, hsl(200, 100%, 30%), hsl(200, 100%, 20%));
        border-color: hsl(200, 100%, 15%);
      }
      .button-primary:hover {
        background: linear-gradient(to bottom, hsl(200, 100%, 25%), hsl(200, 100%, 15%));
        border-color: hsl(200, 100%, 10%);
      }
      .button-secondary {
        background: linear-gradient(to bottom, hsl(200, 10%, 30%), hsl(200, 10%, 20%));
        border-color: hsl(200, 10%, 15%);
      }
      .button-secondary:hover {
        background: linear-gradient(to bottom, hsl(200, 10%, 25%), hsl(200, 10%, 15%));
        border-color: hsl(200, 10%, 10%);
      }
      

      This defines a 1px width solid style border to both buttons. Then, you added a border-color property to customize the colors for the .button-primary, .button-secondary, and their associated :hover state selectors.

      Save these changes to styles.css, then refresh the page in your web browser. As shown in the following image, the buttons now have a bit more definition provided by a matching darker color border:

      Two buttons, one blue and the other gray, with a darker blue and darker gray border surrounding the buttons, respectively.

      Lastly, each border direction is a shorthand as well. This means that -width, -style, and -color can each be applied to a direction property. For example, the longhand property border-right-color will only apply a color to the right side border.

      To work with these directional longhand border properties, return to styles.css in your text editor. Go to the .legal-contents selector block and set the width and style for all four border sides, then customize the colors of each side:

      styles.css

      ...
      .legal-contents {
        height: 50vh;
        max-height: 20rem;
        margin-top: 1.5rem;
        overflow: auto;
        background-color: white;
        border: 1px solid;
        border-top-color: hsl(0, 0%, 65%);
        border-bottom-color: hsl(0, 0%, 100%);
        border-right-color: hsl(0, 0%, 80%);
        border-left-color: hsl(0, 0%, 80%);
        padding: 0.75rem;
        font-family: "Times New Roman", serif;
      }
      ...
      

      In this code, you added border: 1px solid to the end of the file. After that, you additionally created the border-top-color, border-bottom-color, border-right-color, and border-left-color properties. For the values, you used the different hsl() values for grays.

      Save your changes to styles.css, then reload the page in the browser. The scrollable content container now has a dark gray border along the top, a slightly lighter gray on the sides, and a white border on the bottom. This is to give the perception that the content is inset behind the light gray background, causing an effect where the highlight is on the bottom edge, as shown in the following image:

      A box of scrollable content with a dark border on top, a mid-gray border on the sides, and a white border on the bottom.

      In this section, you used the border property and its various longhand variations. You created several borders, which were applied to different sides as needed. In the next section, you will work with the border-radius property, which allows for the corners of containers to be rounded.

      Applying a border-radius

      Rounded corners have been a design aesthetic on the web long before the border-radius property was around to accomplish the task. This property can accept any numerical unit or percentage value, and is a shorthand property like the margin or padding properties. This means each corner can be individually adjusted as needed.

      To begin working with the border-radius property, open styles.css in your text editor. Go to the .disclosure-alert selector block and the border-radius property. Then, set the value to 1.5rem, which will apply that value to all four corners of the property. The highlighted CSS in the following code block shows how this is written:

      styles.css

      ...
      .disclosure-alert {
        ...
        border: 1px solid hsl(0, 0%, 0%);
        border-radius: 1.5rem;
      }
      ...
      

      Save this addition to styles.css then open or refresh index.html in a web browser. Only the bottom two corners will appear to be rounded, while the top two will remain pointed edges. The following image illustrates how this is rendered in the browser:

      Container of content with a large rounded corner on the bottom and straight edges on the top.

      The reason only two rounded corners are visible is due to how descendent elements interact with each other on the web. The browser errs on the side of keeping content visible. The .disclosure-alert does have four rounded corners, but because .disclosure-header is inside the element and does not have rounded corners, it overlaps the rounded corners. A quick fix is to add overflow: hidden to .disclosure-alert, causing the container to clip any descendent containers and content. However, this approach can lead to necessary content becoming illegible or invisible. A better practice is to apply a border-radius to the .disclosure-header class to match the curve of its ancestor’s corner.

      To adjust the overlapping corners, return to styles.css in your text editor. Go to the .disclosure-header selector block and add the border-radius property. Since only the top two corners need adjustment, the value will be 1.5rem 1.5rem 0 0:

      styles.css

      ...
      .disclosure-header {
        ...
        border-top: 1px solid hsl(300, 50%, 35%);
        border-bottom: 1px solid hsl(300, 50%, 5%);
        border-radius: 1.5rem 1.5rem 0 0;
      }
      ...
      

      The extended format of this value will apply a 1.5rem curve to the top-left and top-right corners.

      Save your changes to styles.css and refresh index.html in the browser. The purple header now has a rounded corner and is not covering the main container. A new problem has shown up though, as a white sliver from the parent container is peaking from behind the purple header, as shown in the following zoomed-in image:

      Close-up of a purple rounded corner with a sliver of light gray rounded corner showing.

      The corners for both the .disclosure-alert and .disclosure-header are the same size of 1.5rem, but their widths have a size difference. This size difference is caused by the border on the left and right of the .disclosure-alert element. Since the width of the border is 1px on both sides, the size difference is 2px or 0.125rem. To make the curves match, the border-radius for .disclosure-header needs to be 0.125rem smaller than it is currently. Change the border-radius values of 1.5rem to 1.375rem, as highlighted in the following code block:

      styles.css

      ...
      .disclosure-header {
        background: linear-gradient(hsl(300, 50%, 20%), hsl(300, 50%, 10%));
        padding: 2rem 0.5rem;
        text-align: center;
        color: hsl(300, 50%, 95%);
        border-top: 1px solid hsl(300, 50%, 35%);
        border-bottom: 1px solid hsl(300, 50%, 5%);
        border-radius: 1.375rem 1.375rem 0 0;
      }
      ...
      

      Save this change to styles.css and then refresh the page in the web browser. The sliver of white is now gone and the curves of the two elements meet at the appropriate place. The following zoomed-in screenshot shows how these curves line up:

      Close-up of a purple rounded corner with light purple highlight.

      Lastly, you will apply a rounded corner to the buttons at the bottom of the main container. These buttons will have a pill-shape, with a long, flat top and bottom and full rounded sides. To accomplish, this the border-radius value needs to be a unit-based value larger than the element’s height.

      To make a pill-shaped button, open styles.css in your text editor. In the .button selector block, add the border-radius property and then set the value to 2rem. This can be an arbitrary number as long as it is larger than the computed height, the combination of the font-size, line-height, padding, and border-width that can affect the overall height of an element. The highlighted CSS in following code block shows where to add this property:

      styles.css

      ...
      .button {
        ...
        border: 1px solid;
        border-radius: 2rem;
      }
      ...
      

      There are two things to note about this approach. The first is that a height value is not set on this element. Setting a height value should be avoided as content can and will be in a position of flowing outside the container. By avoiding a set height, the button can grow to match the total content. Second is that this will not work correctly with a percent-based value. Percent-based values on a border-radius property curve a percent of the height and the width, causing an oval shape instead of a rounded corner.

      Save your changes to styles.css, then return to the browser and refresh index.html. The page will now render two oblong, pill-shaped buttons, as show in the following image:

      A blue and gray button with rounded edges on the left and right of each button.

      Throughout this section, you used the border-radius property to apply rounded corners to multiple elements, discovering that a border-radius does not prevent descendent elements from leaving the curved space. You also adjusted the value of a border-radius to match the width of an element when multiple rounded elements are layered on top of one another. In the next section, you will use the text-shadow property to apply drop shadows to text content.

      Using the text-shadow Property

      Applying shadows to text has many uses in everyday web development. Shadows can create depth, a glow effect, or help text standout in places where it might be overlooked. Throughout this section, you will apply text-shadow to multiple elements to create various visual effects.

      The text-shadow property consists of up to four values: x-axis offset, y-axis offset, blur radius, and color. As an example, the values could look like this: 2px 4px 10px red. Of these four values, only the offset values are required. The shadow color by default is the color of the text.

      To begin working with text-shadow, you will start by creating a glow effect on the header. Open styles.css in your text editor and go to the .disclosure-header class selector. Within the selector block, add the following text-shadow property:

      styles.css

      ...
      .disclosure-header {
        ...
        border-radius: 1.375rem 1.375rem 0 0;
        text-shadow: 0 0 0.375rem hsl(300, 50%, 50%);
      }
      ...
      

      A glow effect means the color will emanate from every edge of the text, so the x- and y-axis offset values here are set to 0. You set the blur for the glow to 0.375rem (equivalent to 6px) to give a subtle halo of color to the text. Lastly, the color value was set to a bit darker than the color property: hsl(300, 50%, 50%).

      Save this addition to your styles.css file. Next, open index.html in a web browser. The bold heading text on the purple gradient background now has a glow of a middle purple around it. The follow image illustrates how this effect is rendered in the browser:

      Light pink sans-serif font on a purple background with a light purple glow around the text.

      Next, multiple shadows can be placed on text elements, allowing for the creation of an embossed effect on text. This effect is accomplished by placing a lighter-colored shadow below the object and a darker-colored shadow above.

      To create an embossed effect, return to styles.css in your text editor. The effect will be added to the buttons at the bottom of the container. For the .button-primary, .button-primary:hover, .button-secondary, and .button-secondary:hover selectors, add a text-shadow property. Review the highlighted CSS in the following code block for the values:

      styles.css

      ...
      .button-primary {
        border: 1px solid hsl(200, 100%, 5%);
        background: linear-gradient(to bottom, hsl(200, 100%, 30%), hsl(200, 100%, 20%));
        text-shadow: 0 1px hsl(200, 100%, 50%),
                     0 -1px hsl(200, 100%, 5%);
      }
      .button-primary:hover {
        border: 1px solid hsl(200, 100%, 0%);
        background: linear-gradient(to bottom, hsl(200, 100%, 25%), hsl(200, 100%, 15%));
        text-shadow: 0 1px hsl(200, 100%, 45%),
                     0 -1px hsl(200, 100%, 0%);
      }
      .button-secondary {
        border: 1px solid hsl(200, 10%, 5%);
        background: linear-gradient(to bottom, hsl(200, 10%, 30%), hsl(200, 10%, 20%));
        text-shadow: 0 1px hsl(200, 10%, 50%),
                     0 -1px hsl(200, 10%, 5%);
      }
      .button-secondary:hover {
        border: 1px solid hsl(200, 10%, 0%);
        background: linear-gradient(to bottom, hsl(200, 10%, 25%), hsl(200, 10%, 15%));
        text-shadow: 0 1px hsl(200, 10%, 45%),
                     0 -1px hsl(200, 10%, 0%);
      }
      

      The first shadow is a lighter bottom inset highlight. This is done with the 0 1px offset, then the lighter version of the background gradient hues. Next, you made the shadow above the text with a 0 -1px offset, which pulls the shadow up 1px and uses a darker variation of the background colors.

      Save these changes to styles.css, then refresh the page in your web browser. The text inside the buttons now has a slight highlight below the text and a slight shadow above the text. The combination of these text-shadow values creates the embossed effect as rendered in the following image:

      A blue and gray button with text that appear etched into the buttons.

      In this section, you applied the text-shadow property to a few elements. You created a glow effect on the header and an embossed effect with multiple shadows on the buttons. In the next section, you will apply shadows to HTML elements with the box-shadow property.

      Adding box-shadow to Elements

      Just as the text-shadow property allows for text content to have shadows, the box-shadow property allows for elements and containers to have shadows as well. The box-shadow has two additional features that you will explore throughout this section, including the ability to control the blur’s spread and set the shadow inside the element.

      To begin working with the box-shadow property, open styles.css in your text editor. In the .disclosure-alert selector block, add the box-shadow property. Just like the text-shadow, the x- and y-axis offset values are required, and if a color is not provided, the color property value is used. For this first box-shadow, set the offsets to 0, the blur to 0.5rem, and the color to a dark hsl(300, 40%, 5%), as highlighted in the following code block:

      styles.css

      ...
      .disclosure-alert {
        ...
        border-radius: 1.5rem;
        text-shadow: 0 0 0.375rem hsl(300, 50%, 50%);
        box-shadow: 0 0 0.5rem hsl(300, 40%, 5%);
      }
      ...
      

      Save the changes to styles.css and refresh the page in your web browser. There is now a near black shadow spreading out from the container. Note, too, that the shadow respects and follow the curves you created with the border-radius property. The following image shows how this is rendered in the browser:

      Box of content with a short shadow in black coming from the box.

      Next, return to styles.css and begin creating a more complex effect by adding two additional large glow effects to the box-shadow. Add a comma between each new shadow, setting each to have a y-axis offset of 0.5rem. Then set large blurs and use lighter variations of the blue and purple from the color palette, as highlighted in the following code block:

      styles.css

      ...
      .disclosure-alert {
        ...
        box-shadow: 0 0 0.5rem hsl(300, 40%, 5%),
                    0 0.5rem 6rem hsl(200, 40%, 30%),
                    0 0.5rem 10rem hsl(300, 40%, 30%);
      }
      ...
      

      The order of these shadows matter. The first shadow with the near black color will be presented above the new shadows, and each subsequent shadow is added behind the next.

      Save your changes to styles.css and refresh the page in your browser. As illustrated in the following image, the combination of multiple shadows renders a unique effect:

      Box of content with several compound shadows of varying colors creating a bluish purple dark glow.

      The box-shadow property’s blur spread feature can be used to create a feeling of depth. The spread value accepts both positive and negative values. A negative value spread combined with a strong offset and blur creates a shadow that feels distant and far from the source container.

      To begin, return to styles.css in your text editor. In between the dark small shadow and the larger blue shadow on the .disclosure-alert selector, add the following highlighted CSS from the code block:

      styles.css

      ...
      .disclosure-alert {
        ...
        box-shadow: 0 0 0.5rem hsl(300, 40%, 5%),
                    0 6rem 4rem -2rem hsl(300, 40%, 5%),
                    0 0.5rem 6rem hsl(200, 40%, 30%),
                    0 0.5rem 10rem hsl(300, 40%, 30%);
      }
      ...
      

      This addition to the shadow set keeps the x-axis offset at 0, but moves the y-axis considerably to 6rem. Next, the blur is not as large as the glow, but is at a decent size of 4rem. Then comes to the blur spread value, which in this case is set to -2rem. The default value for the spread is 0, which is equal to the container. At -2rem the spread will condense inward from the container to create a visual effect of depth.

      Save your changes to styles.css, then refresh index.html in the browser. The shadow is a deep purple color that creates a sense that the main content box is floating well above the surface of the moon, as rendered in the following image:

      Box of content with several compound shadows of varying colors creating a bluish purple dark glow and a deep shadow covering a photo of the moon.

      Another use of a box-shadow is to create a slight highlight and shadow bevel effect, like you did earlier with the border property on the header. The advantage of using a box-shadow instead of a border is that it does not affect the box model, which causes shifts in the content flow. It can also be used in conjunction with a border. When using this effect with a border, the inset value must be added to the box-shadow so that the shadow is inside the container.

      To begin using an inset value on the box-shadow, open styles.css in your text editor. This effect will be added to the buttons, so you will be applying these styles to .button-primary, .button-primary:hover, .button-secondary, and .button-secondary:hover. Like the text-shadow, this will consist of a 0 1px and 0 -1px offset combination. The difference is that the word inset can be added to the beginning or the end of the value, as highlighted in the following code block:

      styles.css

      ...
      .button-primary {
        ...
        text-shadow: 0 1px hsl(200, 100%, 50%),
                     0 -1px hsl(200, 100%, 5%);
        box-shadow: inset 0 1px hsl(200, 100%, 50%),
                    inset 0 -1px hsl(200, 100%, 15%);
      }
      .button-primary:hover {
        ...
        text-shadow: 0 1px hsl(200, 100%, 45%),
                     0 -1px hsl(200, 100%, 0%);
        box-shadow: inset 0 1px hsl(200, 100%, 45%),
                    inset 0 -1px hsl(200, 100%, 10%);
      }
      .button-secondary {
        ...
        text-shadow: 0 1px hsl(200, 10%, 50%),
                     0 -1px hsl(200, 10%, 5%);
        box-shadow: inset 0 1px hsl(200, 10%, 50%),
                    inset 0 -1px hsl(200, 10%, 15%);
      }
      .button-secondary:hover {
        ...
        text-shadow: 0 1px hsl(200, 10%, 45%),
                     0 -1px hsl(200, 10%, 0%);
        box-shadow: inset 0 1px hsl(200, 10%, 45%),
                    inset 0 -1px hsl(200, 10%, 10%);
      }
      

      Save these changes to styles.css and then refresh index.html in your browser. The buttons now have a highlight and a shadow, similar to the text. This combined with the gradient background creates a simple, yet distinguished effect for buttons. The following image shows how this is rendered in the browser:

      A blue and gray button with a thin highlight and shadow on the top and bottom of the buttons.

      Lastly, you can also apply a blur spread value to an inset shadow. The spread moves the starting point of the blur outward from the edge, but when using inset the spread moves the starting point inward. This means that when a negative value is applied to the spread on an inset, the shadow expands out of the viewing area of the element. The outward expansion of the spread can create a shadow that looks like a short gradient. This can create the illusion of an element having rounding at the edges as the shadow is applied below the content of the element.

      To begin creating this effect, open styles.css in your text editor. Navigate to the .legal-contents class selector and add a box-shadow property. This shadow will consist of three shadows. The first will set a short shadow around the inside of the whole container, and the next two will provide an elongated light shadow on the top and bottom of the element. The highlighted CSS in the following code block demonstrates how this is set up:

      styles.css

      ...
      .legal-contents {
        ...
        font-family: "Times New Roman", serif;
        box-shadow: 0 0 0.25rem hsl(0, 0%, 80%) inset,
                    0 4rem 2rem -4rem hsl(0, 0%, 85%) inset,
                    0 -4rem 2rem -4rem hsl(0, 0%, 85%) inset;
      }
      ...
      

      Save your changes to styles.css, then refresh the page in the browser. The shadows are now creating an effect that makes the legal text appear set like a window into the container. The shadows also help enhance the border colors that were applied to this element. The following image illustrates how this is rendered in the browser:

      A box of scrollable content with inset shadows to give the illusion of depth.

      In this section, you put the box-shadow property into practice. You also used the blur spread and inset features of box-shadow to allow for more styling options. In the last section, you will implement the outline property, then use box-shadow to make a more versatile outline.

      Using the outline Property

      The last property that affects the edges of elements is the outline property. Across all browsers, the :focus state of elements is made using the outline property. However, each browser’s implementation of the default :focus style varies significantly. The outline property is similar to the border property, except for two key differences: It does not have directional property variations, and it does not affect the box model. The last of those two differences makes it ideal for :focus styles, as it provides a visual indicator of the active element without disrupting the content flow.

      To observe the browser default of a :focus state, open index.html in your browser. Use the TAB key to navigate the page until one of the bottom buttons has focus. Depending on which browser you are using, you may or may not be able to see the default :focus styles. For example, Firefox shows a white dotted outline, but it isn’t perceivable against the light gray background. The following image shows from left to right how the default focus style appears in Firefox, Safari, and Chrome:

      Default focus styles of Firefox, Safari, and Chrome.

      To begin customizing your own :focus state with the outline property, open styles.css in your text editor. Go to the .button class selector and add in the outline property:

      styles.css

      ...
      .button {
        ...
      }
      .button:focus {
        outline: 0.25rem solid hsl(200, 100%, 50%);
      }
      ...
      

      As with the border property, the value for the outline includes a width, style, and color value. Since the goal of a focus state is to bring attention to an element, the width increases to 0.25rem, which is equivalent to 4px. Next, you set the style to solid, so that the focus state is more similar to that of Safari and Chrome. Lastly, you set the color to a deep blue with hsl(200, 100%, 50%).

      Save your changes to styles.css, then return to your browser and refresh the page. Once again, the browser determines how the outline renders. The following image shows what these styles look like in Firefox, Safari, and Chrome, from left to right:

      Custom focus stlyes of Firefox, Safari, and Chrome.

      Across all three browsers, the outline property is displayed quite differently. Firefox holds tight around the whole rounded shape of the button. Safari creates a right-angle box, but touches the edges of the button. Chrome is similar to Safari, but adds some extra space between the button and the outline.

      To create a style that looks like Firefox’s across all browsers requires using box-shadow instead of outline.

      To begin creating a more custom :focus state, return to your styles.css file in your text editor. The first thing to do is disable the browser’s default outline style by changing the value on .button:focus selector’s outline to none, as highlighted in the following code block:

      styles.css

      ...
      .button {
        ...
      }
      .button:focus {
        outline: none;
      }
      ...
      

      Next, go down to the button-primary:hover and button-secondary:hover selectors and add a comma followed by a :focus state variation, as highlighted in the following code block:

      styles.css

      ...
      
      .button-primary {
        ...
      }
      .button-primary:hover,
      .button-primary:focus {
        ...
      }
      .button-secondary {
        ...
      }
      .button-secondary:hover,
      .button-secondary:focus {
        ...
      }
      

      Finally, create two new selectors for each button’s :focus, .button-primary: focus, and .button-secondary:focus. Inside the new selector blocks, add a new box-shadow property with the same inset shadows from their :hover, :focus counterpart. Then, add another shadow to the series with the offsets and blur all set to 0. After that, add a spread of 0.25rem, which will create a solid, non-blurred line around the element. Finally, add the same color to both instances. The highlighted CSS in the following code block show how this is written:

      styles.css

      ...
      
      .button-primary {
        ...
      }
      .button-primary:hover,
      .button-primary:focus {
        ...
      }
      .button-primary:focus {
        box-shadow: inset 0 1px hsl(200, 100%, 45%),
                    inset 0 -1px hsl(200, 100%, 10%),
                    0 0 0 0.25rem hsl(200, 100%, 50%);
      }
      .button-secondary {
        ...
      }
      .button-secondary:hover,
      .button-secondary:focus<^> {
        ...
      }
      .button-secondary:focus {
        box-shadow: inset 0 1px hsl(200, 10%, 45%),
                    inset 0 -1px hsl(200, 10%, 10%),
                    0 0 0 0.25rem hsl(200, 100%, 50%);
      }
      

      Save these changes to styles.css and return to your browser to refresh index.html. Now, as you use the TAB key to navigate through the page. Regardless of the browser, the :focus style on the buttons will now look the same. The following image is how the box-shadow version of an outline appears in the browser along with the whole page:

      The final styling of the content with a blue outline focus state on a blue button at the bottom of the content.

      This last section introduced you to the outline property and how each browser uses it in different ways. At minimum, a :focus indicator is needed for accessibility, and the outline property gets the job done. Expanding on this, you also made a more advanced and visually consistent :focus style by creating a box-shadow with a large spread value.

      Conclusion

      Styling the edges of elements allows the design of a website to gain variance and attention. The border property can help provide definition and separation between content. The border-radius property softens the aesthetic and helps define the attitude of the design. Shadows on text and boxes bring depth and help bring attention to content. Lastly, the outline property provides accessible ways to bring attention to elements with keyboard focus. In this tutorial, you used all these properties to create a visually interesting and useable web page. Understanding each of these properties and how and when to use them will help solve all kinds of front-end interface problems and create new experiences.

      If you would like to read more CSS tutorials, try out the other tutorials in the How To Style HTML with CSS series.



      Source link

      How To Create Layout Features with Position and Z-Index in CSS


      The author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Elements of a website’s user interface (UI) can interact with and overlay on top of one another in many different ways, making CSS layout challenging to control. One way to set the placement of an element and how it overlays other elements is with a combination of the position property, z-index property, and the direction properties, which apply spacing values with top, right, bottom, and left. Experience with these CSS properties will enable you to create UI elements like dropdown navigation bars and figure captions efficiently and quickly.

      In this tutorial, you will create a page of content with a navigation element in the header. The navigation element will include a dropdown sub-navigation component, and the header itself will be affixed to top of the page as the page is scrolled. You will use the position property and its values relative, absolute, and fixed in conjunction with some direction properties to create this effect. Then you will work with the z-index property and to manage element layering with that property.

      Prerequisites

      Setting Up the Example Web Page and Initial position Value

      The default position value for all HTML elements is static, which constitutes the normal flow of content. The static state cannot be affected by a z-index property or any of the direction properties. To introduce more flexibility in your web page’s layout, you will later change the value of position away from this default. In this section, you will create the content for a page of a Lunar travel website and apply a change to the position of an element.

      To begin, open the index.html file in your text editor. Then, add the following HTML to the file:

      index.html

      <!doctype html>
      <html>
        <head>
          <meta charset="utf-8" />
          <title>Destination: Moon</title>
          <link rel="preconnect" href="https://fonts.googleapis.com"> 
          <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 
          <link href="https://fonts.googleapis.com/css2?family=MuseoModerno:wght@400;700&display=swap" rel="stylesheet">
          <link href="styles.css" rel="stylesheet" />
        </head>
        <body>
        </body>
      </html>
      

      In this HTML snippet, the <meta> element defines the character set to use for the text. This will make most special characters, such as accent marks, render without special HTML codes. The <title> element provides the browser with the title of the page. The first three <link> elements load in the custom font Museo Moderno from Google Fonts, and the last loads the styles you will add to your styles.css file.

      Next, fill the page with content so that you have something to style. You will use sample content from Sagan Ipsum as filler copy to work with the styles. Return to index.html in your text editor and add the highlighted HTML from the following code block:

      index.html

      <html>
        <head>
          ...
        </head>
        <body>
          <main>
            <h2>Schedule Your Trip</h2>
            <p>Intelligent beings made in the interiors of collapsing stars vanquish the impossible gathered by gravity not a sunrise but a galaxyrise how far away. Extraordinary claims require extraordinary evidence dispassionate extraterrestrial observer a very small stage in a vast cosmic arena descended from astronomers as a patch of light the ash of stellar alchemy. Concept of the number one citizens of distant epochs with pretty stories for which there's little good evidence with pretty stories for which there's little good evidence the carbon in our apple pies a mote of dust suspended in a sunbeam.</p>
      
            <p>Drake Equation white dwarf something incredible is waiting to be known tesseract quasar dispassionate extraterrestrial observer? Concept of the number one intelligent beings kindling the energy hidden in matter extraordinary claims require extraordinary evidence network of wormholes Euclid? Vanquish the impossible citizens of distant epochs as a patch of light inconspicuous motes of rock and gas made in the interiors of collapsing stars a mote of dust suspended in a sunbeam.</p>
      
            <figure>
              <img src="https://www.digitalocean.com/community/tutorials/images/moon.jpg" alt="The Moon during twilight" />
              <figcaption>Photo by <a href="https://unsplash.com/@ilypnytskyi?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Igor Lypnytskyi</a> on <a href="https://unsplash.com/collections/9479529/moon?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></figcaption>
            </figure>
      
            <p>Citizens of distant epochs rings of Uranus intelligent beings birth take root and flourish across the centuries. Corpus callosum invent the universe as a patch of light the only home we've ever known a mote of dust suspended in a sunbeam made in the interiors of collapsing stars. Kindling the energy hidden in matter Orion's sword Sea of Tranquility great turbulent clouds with pretty stories for which there's little good evidence extraordinary claims require extraordinary evidence.</p>
      
            <p>A billion trillion take root and flourish extraplanetary gathered by gravity hearts of the stars consciousness. Dispassionate extraterrestrial observer Orion's sword are creatures of the cosmos realm of the galaxies descended from astronomers white dwarf. The carbon in our apple pies globular star cluster across the centuries a very small stage in a vast cosmic arena radio telescope vanquish the impossible. Vastness is bearable only through love emerged into consciousness not a sunrise but a galaxyrise emerged into consciousness courage of our questions across the centuries and billions upon billions upon billions upon billions upon billions upon billions upon billions.</p>
          </main>
        </body>
      </html>
      

      The code you just added to index.html creates a headline and four paragraphs that reside inside a <main> element. After the second paragraph, a <figure> element is created to load a moon.jpg image after the second paragraph. The <figure> element also includes a <figcaption> element that contains the citation information for the image. Save your changes to index.html.

      In order to display the image linked here, you will need the Moon Image. First, make an images directory in the same folder as your index.html file:

      Use your browser to download this file to your newly created images directory, or use the following curl command to download it via the command line:

      • curl -sL https://assets.digitalocean.com/articles/68084/moon.jpg -o images/moon.jpg

      Now that you have your image, open your web browser. Select the File menu item and then select the Open option to load your index.html file in the browser. The following image demonstrates how this HTML will render in the browser:

      Four paragraphs of text content in a black serif font on a white background with a photo of the moon between two of the paragraphs.

      Next, you will begin writing your styles. Return to your text editor and open styles.css. The following code block contains the beginning styles for the body, main, figure, img, and h2 elements:

      styles.css

      body {
        margin: 0;
        font: 1rem / 1.5 sans-serif;
      }
      
      main {
        margin: 6rem auto;
        width: 95%;
        max-width: 75ch;
        font-size: 1.125rem;
      }
      
      figure {
        margin: 2rem 0;
        padding: 0;
      }
      
      img {
        max-width: 100%;
        display: block;
      }
      
      h2 {
        font: 400 1.875rem/1.25 MuseoModerno, sans-serif;
        color: hsl(300, 40%, 30%);
      }
      

      Save your additions to styles.css, then return to your browser and refresh index.html. The styles will now be coming together, with a default font sizing set, the content area centered to the page, and the image taking an appropriate amount of space. The following image demonstrates how this is rendered in the browser:

      Four paragraphs of text content in a black sans-serif font on a white background with a photo of the moon between two of the paragraphs.

      Return to styles.css in your text editor. Then, add the highlighted CSS from the following code block to define the caption for your moon image:

      styles.css

      ...
      figcaption {
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      
      figcaption a {
        color: inherit;
      }
      

      The figcaption element selector sets up the image as an inline-block to make it only as wide as its content. The styles on the figcaption also set the background to a dark purple with white text, with a bit of padding all around. Then, the figcaption a descendant selector sets the color value to inherit so that it uses its parent’s white instead of the default blue.

      Save your addition to styles.css and refresh index.html in the browser. The <figcaption> element will now be displayed as a dark background block with some white text, as shown in the following image:

      Photo of the mooon with a black box below the photo containing white sans-serif text.

      Next, to begin working with the position property, return to styles.css in your text editor. In the figcaption element selector block, add the position property. Then use the relative value, as highlighted in the following code block:

      styles.css

      ...
      figcaption {
        position: relative;
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      ...
      

      The relative value for the position property behaves the same as static when it comes to the flow of content. But unlike the static default value, the relative value can use the direction properties and z-index property in order to shift placement and layering options.

      Save this change to your styles.css and return to the browser to refresh index.html. You will find there is no difference made by the new property.

      In this section, you set up the initial HTML and CSS for the project. You also wrote your first position property, setting the ficaption value to relative. In the next section, you will apply the direction properties to move and position the figcaption content over the image.

      Placing Elements with the Direction Properties

      There are four direction properties: top, bottom, right, and left. These properties only work with elements that have a position set to any valid value other than static. Each of these four properties accept any unit-based positive or negative numerical value, including percentages. They also accept a keyword value of auto, which can be used to set these properties back to their default. In this step, you will use these properties to move the figcaption element in one of those four directions.

      To begin using a direction property, open styles.css in your text editor. Return to the figcaption element selector and add a top property after the position property and value:

      styles.css

      ...
      figcaption {
        position: relative;
        top: -4rem;
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      ...
      

      In this code, you set the value for top to -4rem. A positive value on the top property will push the element down from the top, but a negative value pulls the element up away from the top edge of its initial placement.

      Save your changes to styles.css, then open index.html in your web browser. The caption information is now overlaying the photo and hugging the left side, as shown in the following image:

      Photo of the mooon with a black box overlaying the photo containing white sans-serif text.

      The element is along the left side because this browser’s default language is set to a left-to-right direction. If the browser or page were set up for a right-to-left language instead, the position element would be on the right side of the image.

      With the position value set to relative, the influence of the direction properties is limited. When setting a direction property value to 0, the expected and intended result is for the element to be along that side with no spacing, but the relative value will only do this if it does not interrupt the normal flow of the page’s content.

      To see this limitation in practice, remove the top property and add the following right and bottom properties:

      styles.css

      ...
      figcaption {
        position: relative;
        right: 0;
        bottom: 1rem;
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      ...
      

      In this snippet, you set the right property to a value of 0. Next, you added a bottom property with a value of 1rem. Save your changes to styles.css and then refresh index.html in your browser. The expected behavior is for the <figcaption> element to be on the right side and hover a little bit above the bottom of the photo. However, as the following image displays, the element is still on the left side and is only barely over the photo:

      Photo of the mooon with a black box overlaying the bottom left corner of the photo containing white sans-serif text.

      In this section, you used three of the four direction properties to move the <figcaption> element over the photo. Direction properties can only be used on position elements that use a keyword value other than static, and the direction properties are limited in where all content can be aligned with the relative value. In the next section, you will change the position value from relative to absolute to fix this problem.

      Using the relative and absolute Relationship

      The position values of static and relative are similar in how they interact with the flow of content on the page. You can use direction properties with the relative value to move an element in the page layout, but this movement will not disrupt the flow of content. In this section, you will use the absolute value to more precisely control and adjust how an element works with the content of the page.

      Open styles.css in your text editor and go to the figcaption element selector. Then, change the position property value from relative to absolute, as highlighted in the following code block:

      styles.css

      ...
      figcaption {
        position: absolute;
        right: 0;
        bottom: 1rem;
        display: inline-block;
        color: white;
        background-color: hsl(210, 40%, 10%);
        padding: 0.25rem 1rem;
      }
      ...
      

      Save this property value to styles.css. Next, return to your browser to refresh index.html. The element is now on the right side of the whole page and is aligned with the bottom of the window when scrolled to the top of the page. The following image showcases how this code change is rendered in the browser:

      Text content in sans-serif with a black box with white text in the bottom right corner.

      When you change the position value from relative to absolute, the absolute element needs a context from which to apply the direction property values. The context is defined by an ancestor element that also has a position value. When the browser cannot find an ancestor with a position value, the context becomes the browser’s window. In this case, the bottom value places the element 1rem up from the bottom of the browser window. Then, the right property set the element along the right edge of the window.

      In order to have the <figcaption> overlay the photo and be aligned to the photo’s right-most edge, the context needs to change. You can do this by applying the position property to the closest ancestor element set to a value of relative. This will provide the <figcaption> element a starting point for the direction properties to move the element.

      To begin setting a new context for the <figcaption> element, return to styles.css in your text editor. Next, go to the figure element selector, since the <figure> element is the closest ancestor of <figcaption>. In the figure selector block, add a new position property set to the value relative, as highlighted in the following code block:

      styles.css

      ...
      figure {
        margin: 2rem 0;
        padding: 0;
        position: relative;
      }
      ...
      

      Save this update to styles.css then refresh index.html in the web browser. The <figcaption> moves from the bottom right corner of the page to the bottom right corner of the photo. The following image shows how change is rendered in the browser:

      Photo of the mooon with a black box overlaying the bottom right corner of the photo containing white sans-serif text.

      You have now controlled the placement of an absolute positioned element by using the combination of relative and absolute to fine-tune where the intended element is placed. In the next section, you will use what you learned to create a more advanced use of absolute positioning to make a hover-based dropdown navigation.

      Making a Dropdown Navigation Bar with absolute Positioning

      One of the more common uses for the position property is for a dropdown navigation system. In this section, you will write the HTML and then the styles to create a site header with a dropdown navigation that is activated by a hover interaction.

      To begin creating dropdown navigation, open index.html in your text editor. Then create a <header> element before the <main> element inside the <body> tags. Inside the <header> you will create an <h1> title for the page, followed by a <nav> tag filled with a nested unordered list:

      index.html

      <!doctype html>
      <html>
        <head>
          ...
        </head>
        <body>
          <header>
            <h1>Destination: <strong>Moon</strong></h1>
            <nav>
              <ul class="nav nav-main">
                <li class="item-top">
                  <a href="#" class="link link-top">Base Station</a>
                </li>
                <li class="item-top">
                  <a href="#" class="link link-top">Travel Packages</a>
                  <ul class="nav nav-sub">
                    <li>
                      <a href="#" class="link link-sub">Apollo Sights</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Great Craters</a>
                    </li>
                    <li>
      <a href="#" class="link link-sub">Mare the Merrier</a>
                    </li>
                  </ul>
                </li>
                <li class="item-top">
                  <a href="#" class="link link-top">Accommodations</a>
                  <ul class="nav nav-sub">
                    <li>
                      <a href="#" class="link link-sub">The Armstrong Hotel</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Lunar Lander Lodge</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Tranquility Inn</a>
                    </li>
                  </ul>
                </li>
                <li class="item-top">
                  <a href="#" class="link link-top">Plan Your Trip</a>
                  <ul class="nav nav-sub">
                    <li>
                      <a href="#" class="link link-sub">Seasonal Rates</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Food and Restaurants</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Gravity Acclimation</a>
                    </li>
                    <li>
                      <a href="#" class="link link-sub">Recommended Duration</a>
                    </li>
                  </ul>
                </li>
              </ul>
            </nav>
          </header>
      
          <main>
            ...
          </main>
        </body>
      </html>
      

      The list elements contain the several classes you will use to create the styles. Save these additions to index.html.

      Next, open styles.css in your text editor. This site header and navigation will use a couple instances of CSS Flexbox to create a side-by-side layout for elements that are stacked vertically be default. Add the highlighted CSS from the following code block to the bottom of your styles.css file:

      styles.css

      ...
      header {
        font: 1.125rem / 1.25 MuseoModerno, sans-serif;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 2rem;
        color: white;
        background: linear-gradient(250deg, hsl(300, 40%, 10%), hsl(300, 40%, 20%));
      }
      
      h1 {
        margin: 0;
        font-size: 1.75rem;
        font-weight: 400;
      }
      
      .nav {
        margin: 0;
        padding: 0;
        list-style: none;
      }
      
      .nav-main {
        display: flex;
        align-items: stretch;
      }
      
      .item-top {
        position: relative
      }
      

      This header selector defines the font values for all text in the <header> element. Then the display, align-items, and justify-content properties lay out the header with flex so the contents are in a horizontal row, centered to each other. They also make the <h1> and <nav> elements occupy opposing ends of the container. The h1 selector defines the site title styles, and the .nav class selector removes the default unordered list styles. The .nav-main class puts the top level navigation items in a flex row of their own. Lastly, the .item-top class selector defines the top-level <li> as a position: relative context.

      Continuing in your styles.css file, the next set of styles will hide the sub-navigation and create the link styles:

      styles.css

      ...
      .nav-sub {
        display: none;
      }
      
      .link {
        color: inherit;
        display: block;
        text-decoration: none;
      }
      
      .link-top {
        padding: 1.25rem 1.5rem;
      }
      
      .link-sub {
        padding: 0.75rem 1.5rem;
      }
      
      .item-top:hover .link-top,
      .item-top:focus .link-top,
      .item-top:focus-within .link-top {
        background-color: black;
      }
      
      .link-sub:hover,
      .link-sub:focus {
        background-color: hsl(210, 40%, 20%);
      }
      

      The first task for these rules is to hide the dropdown sub-navigation by using the display: none property and value, since the dropdown portion needs to be hidden until hovered. Then you create a series of class selectors to apply the styles for the visible top level links and the hidden nested links. The .link class removes the default <a> styles from all links in the navigation. Then, the .link-top and .link-sub rules define the padding needed for each link at the two levels.

      Next, the grouping combinator that includes .item-top:hover .link-top provides a background color to the link when its parent <li> element is hovered, has focus, or has a descendant that is focused. The states are on the <li> and not the <a> because the interactive state styling remains on the <a> after the cursor or focus moves to the sub-navigation items. Lastly, .link-sub:hover, .link-sub:focus defines the background-color change for the sub-navigation links when hovered or focused.

      Save your changes to styles.css, then open index.html in your browser. The page will now have a dark purple bar crossing the top of the page, with a large site title to the left and a sequence of navigation items to the right, as shown in the following image:

      Purple box containing a text in futuristic font above an area with a white background containing paragraphs of text in a black sans-serif font.

      Next, return to styles.css in your text editor to create the styles for the sub-navigation dropdown effect:

      styles.css

      ...
      .link-sub:hover,
      .link-sub:focus {
        background-color: hsl(210, 40%, 20%);
      }
      
      .item-top:hover .nav-sub,
      .item-top:focus .nav-sub,
      .item-top:focus-within .nav-sub {
        display: block;
        position: absolute;
      }
      

      In this code, you are appending a group combinator selector .item-top:hover .nav-sub to your CSS, along with state variations for :focus and :focus-with in place of :hover. When the <li> element is hovered or has focus, the nested <ul> should change the display property from none to block to make it visible. Additionally, the sub-navigation should not disappear when the focus moves from the top level, which is where :focus-within helps. Next, you added the position property set to absolute, as this will need to have more precise positioning control.

      Next, since the the desired outcome is to have the dropdown always start at the very bottom of the <header> element, a top property needs to be added set to 100%, in addition to a few more rules:

      styles.css

      ...
      
      .item-top:hover .nav-sub,
      .item-top:focus .nav-sub,
      .item-top:focus-within .nav-sub {
        display: block;
        position: absolute;
        top: 100%;
        right: 0;
        width: 15rem;
        background-color: black;
      }
      

      A top property set to 100% will move the absolute element so that its top starts at the relative ancestor’s bottom. Then, since the top-level navigation will be all the way to the right, a right property set to 0 is necessary so that the width of the dropdown does not disrupt the horizontal width of the page by going offscreen. Lastly, you added a width value set to 15rem and a background-color set to black.

      Save these changes to styles.css, then return to the browser and refresh index.html. You can now interact with the navigation by hovering your cursor over the top-level elements and then moving the cursor vertically to the sub-navigation items. Additionally, if you use the TAB key on your keyboard, you will be able to cycle through each top-level and sub-level navigation item. The following animation shows how this will appear while using keyboard navigation to focus on each navigation item:

      Animation showing a cursor hovering over text in a purple box causing a black box with white text to appear.

      Throughout this section, you created a dropdown sub-navigation system using the power of the absolute positioning value and two direction properties. You also used the value of 100% on the top property to push the sub-navigation to always show up below the header bar. In the next section, you will use the fixed value for the position property to make the header bar stay affixed to the top of the page while scrolling.

      Using the fixed Value

      Another common use for the position property is to implement the fixed value to make an element stay within the viewport, no matter the scroll position. This value is often used when creating features such as alert banners, which need to be visible no matter where the user is on the page. In this section, you will use the fixed value to keep the header in the viewport at all times. This will provide quicker access to the navigation throughout the user’s experience.

      To begin using the fixed positioning value, return to styles.css in your text editor. Go to the header element selector and at the top of the selector block, add the position property with the fixed value. Since the goal is for the header to be attached to the top of the page, add a top property set to 0, as highlighted in the following code block:

      styles.css

      ...
      header {
        position: fixed;
        top: 0;
        font: 1.125rem / 1.25 MuseoModerno, sans-serif;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 2rem;
        color: white;
        background: linear-gradient(250deg, hsl(300, 40%, 10%), hsl(300, 40%, 20%));
      }
      ...
      

      Save these additions to stlyes.css, then open index.html in your web browser. When the page finishes rendering, begin scrolling the page up and down to show how the header remains fixed to the top of the viewport window. The following animation demonstrates how this effect appears in the browser:

      Animation of a purple box remaining stationary as content of the page is scrolled.

      There is one issue with the header now that it has a position: fixed added: it no longer spans the full width of the window. One of the side-effects of using the fixed value is that it causes the element to condense down as far as it can. There are a couple of solutions, one of which is to add a width property set to 100%. But this can cause horizontal scrolling if the element has padding and the default box model.

      Instead, add a left and right property, each set to 0:

      styles.css

      ...
      header {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        font: 1.125rem / 1.25 MuseoModerno, sans-serif;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 2rem;
        color: white;
        background: linear-gradient(250deg, hsl(300, 40%, 10%), hsl(300, 40%, 20%));
      }
      ...
      

      This will stretch out the header to be affixed to the left and right edges of the viewport.

      Save your changes to styles.css, then refresh index.html in the browser. The header once again will span edge-to-edge and remain visible while scrolling down the page. The dropdown navigation continues to work the same no matter how far down the page the user scrolls, as shown in the following animation:

      Animation of a purple box remaining stationary as content of the page is scrolled, with the cursor hovering white text in the purple box to reveal a black box with white text below.

      You’ve now effectively created a fixed header, allowing the navigation to be accessible regardless of where on the page the user is. You also learned that position: fixed requires additional styles in order to stretch to each side of the browser. In the last section, you will use the z-index property to control how position elements overlap each other.

      Layering Elements with z-index

      The hardest part of working with the position property is having multiple position elements on a page and managing the order in which they should overlap. By default, the browser layers these elements by putting each position element it encounters further down the HTML page in front of those that came before it. In this section, you will use the z-index property to change this default layering. You will also use custom CSS variables to track layer ordering.

      When scrolling the page down with the position: fixed header, there is a large issue that occurs once you scroll far enough down that the moon photo and the header meet. The expectation is that the fixed header will overlap the relative photo, but the actual behavior is the other way around:

      Animation of a stationary purple box with white text as the page is scrolled. The photo of the moon passes over top of the stationary purple box.

      The reason the photo is overlapping the header is due to the HTML order. Each position element of relative, absolute, or fixed value is set as a series of planes added one in front of each other along the z-axis. A fix to this issue could be achieved by moving the navigation to the bottom of the page, since the position: fixed would visually keep the header at the top. However, the z-index property exists to control this kind of situation. The z-index value is a whole number value that defines the order in the z-axis stack the element will occupy.

      All elements set to relative, absolute, and fixed are given a default z-index value of 0, but when there is more than one element along the same plane, the stack renders based on markup order. Using small z-index values such as z-index: 1 for the photo and z-index: 2 for the header will fix this issue, but since the z-index value must be a whole number, there would be no room for another element to fit in between the two. One method to add flexibility to your styling is to use a 100-based system to increment z-index values with the use of CSS variables.

      To create your own z-index system, open styles.css in your text editor. Then, at the top of the file create a :root selector, which is a pseudo-class selector that applies styles to the top-most HTML element on the page, most commonly the <html> element. Inside, create a series of CSS custom properties, also known as CSS variables:

      styles.css

      :root {
        --z-1: 100;
        --z-2: 200;
        --z-3: 300;
        --z-4: 400;
        --z-5: 500;
        --z-6: 600;
        --z-7: 700;
        --z-8: 800;
        --z-9: 900;
      }
      ...
      

      As shown in this code, custom properties start with two hyphen symbols, followed by a custom name. For the z-index system, you created a series that begins with z, followed by another hyphen, then a number ranging from 1 to 9. For the value of each custom property, you set it to the one hundred value of the corresponding range: 100 for 1, 200 for 2, and so on. The purpose for this 100-based incrementation is to allow a large amount of possible space between each level of the system. If there is ever a situation where a position element needs to go between --z-3 and --z-4, then there are 99 possible values to accomodate that situation.

      Next, go to the figure element selector in your styles.css file. To use the values of the custom properties, first add a z-index property. Then, to implement the system, add a var() as the value for the z-index property:

      styles.css

      ...
      figure {
        margin: 2rem 0;
        padding: 0;
        position: relative;
        z-index: var(--z-1);
      }
      ...
      

      var() in CSS declares that the value will be defined by a custom property. Inside the parentheses of the var(), you added the first property from the :root ruleset: --z-1. This defines the bottom layer of the z-index system and doesn’t change the visual ordering just yet.

      Next, go to the header selector and add a z-index property with the same format to load the --z-9 custom property value.

      styles.css

      ...
      header {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        z-index: var(--z-9);
        font: 1.125rem / 1.25 MuseoModerno, sans-serif;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 2rem;
        color: white;
        background: linear-gradient(250deg, hsl(300, 40%, 10%), hsl(300, 40%, 20%));
      }
      ...
      

      Since --z-9 is the highest number in the system, the <header> element will always be above all other position elements. One thing to note is that the z-index value is only placed on three of the five position elements. This is because a z-index is only needed per position context. The figure and the header are the topmost position elements on the page, with the body being the initial position context. The remaining nested position elements will travel with their ancestor to the appropriate z-axis plane.

      Save your changes to styles.css, then return to your browser to reload index.html. Now, as you scroll the page, the photo of the moon and its caption now travel under the header and its open sub-navigation items. The following animation demonstrates the new overlapping scenario:

      Animation of a stationary purple box with white text as the page is scrolled. A photo of the moon passes underneath of the stationary purple box.

      In this final section, you used custom properties to create a z-index system to better control which position elements overlap which. You also used a CSS variables method to accomodate projects with a large number of position elements by incrementing z-index values by 100.

      Conclusion

      The position property provides a number of ways to create unique layouts and interactions. In this tutorial, you put to practice the position property values of relative, absolute, and fixed. You worked through examples of how each interacts with the page and each other in different ways. You also used the direction properties top, right, bottom, and left to fine-tune the placement of position elements on the page and in relation to each other. Finally, you used the z-index property to control the layering order of the position elements. These tools will be valuable in your front-end development practice to solve many kinds of other solutions, including modals, alert banners, and sticky elements.

      If you would like to read more CSS tutorials, try out the other tutorials in the How To Style HTML with CSS series.



      Source link