One place for hosting & domains

      Model

      How To Use the Display Property to Manipulate the Box Model in CSS


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

      Introduction

      HTML and CSS work together to render visual elements of a web page in the browser. HTML elements carry computational and hierarchical meaning and have default styles the browsers apply to these elements. Among these default styles is the display property. The value of this property affects the box model, the mechanism that determines how elements interact with one another on a page. Using the display property, you can efficiently control how an element interacts with the layout of your web page, allowing you to create more flexible solutions for situations like responsive mobile web design.

      In this tutorial, you will work through multiple demos using the display property and learn how it determines flow interactions with other elements. You will begin with the foundational values of display: block and inline. You will then use the combination value of inline-block to learn about the possibilities of the inline- prefixed values. Next, you will learn about the power and danger of using the none value. Lastly, you will use a max-width media query to transform a table into a display: block view on a small screen.

      Prerequisites

      Setting Up the Initial HTML and CSS files

      To begin, you will set up the HTML and CSS files that you will use throughout the tutorial. You will also explore the default display values of text-containing elements.

      Start by opening index.html in your text editor and adding the following code to your file:

      index.html

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

      This code sets up the framework necessary for every HTML document. The information contained in the <head> element defines the page’s name in the <title> element and where to load the stylesheet, which is determined in the <link> element. The <meta> tags define the character encoding and small screen device handling, respectively. The main content of the page will be added inside the <body> tags throughout the tutorial.

      Next, inside the <body> element, create a <main> element with a class attribute set to content-width. You will use this element to handle the layout of the content within the page. Inside the <main> element, create an <h1> tag pair followed by a <p>. Within the <h1> and <p> elements, add the content shown in the following code block:

      index.html

      <!doctype html>
      <html>
        <head>
          ...
        </head>
        <body>
          <main class="content-width">
            <h1>The Terrestrial Planets of the Solar System</h1>
      
            <p>
              The four inner planets of the Solar System consist of Mercury, Venus, Earth, and Mars. These planets are known as terrestrial due to their hard, rocky surface. Compared to the gaseous planets of the outer solar system, the inner terrestrial planets are significantly smaller in size. Depending on tectonic activity and presence of liquids these planets will have features such as canyons, mountains, and volcanoes on their surface.
            </p>
          </main>
        </body>
      </html>
      

      Highlighted code, like that in the previous code block, is used throughout this tutorial to emphasize changes to the code.

      Save your changes to index.html, then create a new file called styles.css and open it in your editor as well.

      In your styles.css file, you will add selectors for the elements you created in index.html. Create a selector for body and .content-width, then add the styling properties as demonstrated in the following code block:

      styles.css

      body {
        margin: 0;
        font-family: sans-serif;
        line-height: 1.5;
        color: hsl(215, 5%, 20%);
        background-color: hsl(215, 5%, 98%);
      }
      
      .content-width {
        margin: 2rem auto;
        width: 90%;
        max-width: 40rem;
      }
      

      The styles for the body element reset some default layout and text styling with the margin, font-family, and line-height properties. The color and background color add a dark-gray blue and a light-gray blue to the page. The .content-width properties will keep it centered to the page, taking up 90% of the screen width until it reaches a maximum size of 40rem, or 640px.

      Next, add some font styling to make the text more legible:

      styles.css

      ...
      .content-width {
        margin: 2rem auto;
        width: 90%;
        max-width: 40rem;
      }
      
      h1 {
        font-size: 2rem;
        font-weight: 400;
        line-height: 1.2;
      }
      
      p {
        font-size: 1.125rem;
      }
      

      The h1 properties define the size and weight of the text and bring the line-height property down to a better spacing for headings. Lastly, the p element selector bumps up the font-size to 1.125rem, or 18px.

      Save your changes to styles.css, then open your web browser. Open index.html in the browser by dragging the file into the browser window or using the browser’s Open File option. The browser will render the HTML and CSS code to produce a page like the following image:

      Large header text and smaller paragraph text in a dark blue-gray color on a light gray background.

      So far, the HTML elements that you have worked with are known as block elements. These are elements that create defined areas of content that take up the full width of the parent container. Additionally, block elements are usually rendered by themselves on a new line. This means that added block elements stack toward the end of the page. For a top-to-bottom, left-to-right language like English, block elements stack toward the bottom of the browser window.

      Next, you will add inline elements, which are elements that exist within the flow of text content. Since inline elements do not take up the entire width of their parent, and since they are not rendered on their own lines, they are added in the direction of the text flow. For English, this is a left-to-right direction.

      Where block elements define the meaning and group of content, like a paragraph, inline elements provide context about a word or group of words, such as an emphasis.

      Return to index.html in your text editor. In the second sentence, wrap the word terrestrial in the emphasis tag, <em>. Then, in the third sentence, wrap the phrase gaseous planets in an anchor tag, <a>. In the opening <a> tag add an href attribute with a value of https://en.wikipedia.org/wiki/Giant_planet. This will link to the Wikipedia page on the topic. The highlighted HTML in the following code block demonstrates how this is set up:

      index.html

      ...
      <p>
        The four inner planets of the Solar System consist of Mercury, Venus, Earth, and Mars. These planets are known as <em>terrestrial</em> due to their hard, rocky surface. Compared to the <a href="https://en.wikipedia.org/wiki/Giant_planet">gaseous planets</a> of the outer solar system, the inner terrestrial planets are significantly smaller in size. Depending on tectonic activity and presence of liquids these planets will have features such as canyons, mountains, and volcanoes on their surface.
      </p>
      ...
      

      Save these additions to index.html then, return to styles.css in your text editor. To demonstrate the difference between block and inline elements, create an a element selector. Inside the selector add the display property set to block, as demonstrated in the following code block:

      styles.css

      ...
      p {
        font-size: 1.125rem;
      }
      
      a {
        display: block;
      }
      

      Save your change to styles.css, then return to the page in your web browser. Refresh the page to load the latest version of your code. The page demonstrates the key difference between a block and an inline element, as the link set to display: block now occupies its own line. This is demonstrated in the following image:

      Large header text and smaller paragraph text in a dark blue-gray color on a light gray background with a blue underlined text breaking up the paragraph into two sections.

      The primary difference between a block and an inline value is that a block breaks the current content flow while inline maintains it. Additionally, if a width property were applied to the a selector, it would not change the layout. When the content flow is disrupted by a block element, it remains broken, and the width always takes up the entire parent container width.

      inline and block are the most common browser default values. While the display property has many values, with a few exceptions, all remaining elements use one of these two values.

      Now that you have explored the differences between block and inline, return to styles.css in your text editor. In the a selector, remove the display: block and replace it with a color property with a value of hsl(215, 80%, 50%), which is a richer version of the blue used on the body. Then create an a:hover selector with a text-decoration property set to none. This will remove the underline when the link is hovered. The highlighted CSS in the following code block shows how this is written:

      styles.css

      ...
      a {
        color: hsl(215, 80%, 50%);
      }
      
      a:hover {
        text-decoration: none;
      }
      

      Save your changes to styles.css and refresh index.html in your web browser. The link will once again be inline with the text and will now be a lighter blue color, as shown in the following image:

      Large header text and smaller paragraph text in a dark blue-gray color on a light gray background with a blue underlined link.

      In this section, you set up the HTML and CSS files you will use throughout the tutorial. These files will be amended and modified regularly, so keep both files open in your text editor and remember to save regularly. You also learned about the default display values, inline and block, and changed the value of an inline element to block. In the next section, you will use the inline-block value, which combines the capabilities of inline and block.

      Using the inline-block Value

      Next, you will create a button element with a customizable width, rather than a button that takes up the whole width of the parent container. To do this, you will use the inline-block value, which maintains box model properties of the block value like margin and padding while also having the content flow properties of the inline value.

      The inline- prefix is available on several display values, including inline-flex, inline-grid, and inline-table. The inline-block value defines the box model of the element as a block, but it does not disrupt the content flow. Additionally, inline-block does not take up the full parent width, as block does. Instead, the inline-block element condenses down to only the width of its content. For shorter content, such as a button, this makes for a useful resizing of the element with block box model properties, such as margin.

      To begin working with inline-block, open index.html in your text editor. After the closing <p> tag, add an <a> tag with a class attribute set to button and an href attribute set to https://en.wikipedia.org/wiki/Terrestrial_planet. Inside that tag, add the text Learn more on Wikipedia. The highlighted HTML in the following code block demonstrates how this is written:

      index.html

      <div class="content-width">
        <h1>The Terrestrial Planets of the Solar System</h1>
      
        <p>
          ...
        </p>
      
        <a href="https://en.wikipedia.org/wiki/Terrestrial_planet" class="button">Learn more on Wikipedia</a>
      </div>
      

      Save your changes to index.html, then open styles.css in your text editor.

      In your styles.css file, add a class selector for .button. This will style the link you created in your index.html file. By default, an <a> has a display value of inline. For this step, change the display value to block for the button class, then add the additional highlighted styles from the following code block:

      styles.css

      ...
      a:hover {
        text-decoration: none;
      }
      
      .button {
        display:block;
        padding: 0.5rem 1.25rem;
        text-align: center;
        text-decoration: none;
        color: hsl(215, 20%, 95%);
        background: linear-gradient(to bottom, hsl(215, 80%, 60%), hsl(215, 80%, 40%));
      }
      

      The additional styles added to the .button element add padding, center the text, and remove the link underline. Additionally, the styles add a blue gradient of the same hue as the earlier versions of this blue with a near white text color.

      Save these changes to the styles.css, then return to your browser and refresh index.html. The button will fill the full width of the content area with a blue gradient. The following image shows how this will render in the browser:

      Large header text and smaller paragraph text in a dark blue-gray color on a light gray background with a blue button below the paragraph with white text. The button is as wide as the paragraph.

      Next, you will change the block value for the display property to inline-block. Return to styles.css in your text editor and change the display property value from block to inline-block, as highlighted in the following code block:

      styles.css

      ...
      .button {
        display: inline-block;
        padding: 0.5rem 1.25rem;
        text-align: center;
        text-decoration: none;
        color: hsl(215, 20%, 95%);
        background: linear-gradient(to bottom, hsl(215, 80%, 60%), hsl(215, 80%, 40%));
      }
      

      Save these changes to styles.css and then refresh index.html in your web browser. The width of the button has condensed from extending the full width of its parent to being just as wide as its content, plus the padding value. The following image demonstrates how the inline-block element renders in the browser:

      Large header text and smaller paragraph text in a dark blue-gray color on a light gray background with a blue button below the paragraph with white text. The button is only as wide as the text inside the button.

      Finally, return to styles.css to add in some last styling for the button. You will add styles to apply a 3D effect to the button by adding a border-radius, border, text-shadow, and box-shadow. Also, create a .button:hover selector and add a box-shadow and linear-gradien() that make a darker hover state. The highlighted CSS in the following code block show how to write these styles:

      styles.css

      ...
      .button {
        display: inline-block;
        padding: 0.5rem 1.25rem;
        text-align: center;
        text-decoration: none;
        color: hsl(215, 20%, 95%);
        background: linear-gradient(to bottom, hsl(215, 80%, 60%), hsl(215, 80%, 40%));
        border-radius: 0.25rem;
        border: 1px solid hsl(215, 80%, 35%);
        text-shadow: 0 -1px hsl(215, 80%, 35%);
        box-shadow: 0 1px hsl(215, 80%, 70%) inset;
      }
      
      .button:hover {
        box-shadow: 0 1px hsl(215, 80%, 60%) inset;
        background: linear-gradient(to bottom, hsl(215, 80%, 50%), hsl(215, 80%, 30%));
      }
      

      Save your changes to styles.css and then refresh the page in your web browser. Visually, the button now has more definition and depth, as shown in the following image:

      Blue gradient button with white text and a dark border.

      In this section, you used the inline-block value on a link to create a button that is large and clickable, but only as wide as the link’s text. You also learned how there are other inline- prefixed display values that allow for various display types that do not disrupt the content flow. In the next section, you will continue changing display values by switching table elements to block.

      Changing a Table to Use display: block

      Next, you will convert a whole table to use the display: block property value. A table requires HTML specific to the table element, and each child element of the table has its own default display value. For example, the <table> element has a display value of table, and the table cell, <td>, has a display value of table-cell. There can be many reasons why a table might need to change its display value, but most often it is for a small-screen device solution where the table doesn’t fit well.

      To begin working with a table’s display property, open index.html in your text editor. After the button link, add the highlighted HTML from the following code block:

      index.html

      ...
      <a href="https://en.wikipedia.org/wiki/Terrestrial_planet" class="button">Learn more on Wikipedia</a>
      
      <table>
        <caption>
          Terrestrial Planets Statistics
        </caption>
        <thead>
          <tr>
            <th>Name</th>
            <th>Radius</th>
            <th>Moons</th>
            <th>Gravity</th>
            <th>Wikipedia</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <th>Mercury</th>
            <td>2,439.7 km</td>
            <td>0</td>
            <td>3.7 m/s<sup>2</sup></td>
            <td>
              <a href="https://en.wikipedia.org/wiki/Mercury_(planet)" class="button">
                Learn More
              </a>
            </td>
          </tr>
          <tr>
            <th>Venus</th>
            <td>6,051.8 km</td>
            <td>0</td>
            <td>8.87 m/s<sup>2</sup></td>
            <td>
              <a href="https://en.wikipedia.org/wiki/Venus_(planet)" class="button">
                Learn More
              </a>
            </td>
          </tr>
          <tr>
            <th>Earth</th>
            <td>6,371.0 km</td>
            <td>1</td>
            <td>9.80665 m/s<sup>2</sup></td>
            <td>
              <a href="https://en.wikipedia.org/wiki/Earth_(planet)" class="button">
                Learn More
              </a>
            </td>
          </tr>
          <tr>
            <th>Mars</th>
            <td>3,389.5 km</td>
            <td>2</td>
            <td>3.72076 m/s<sup>2</sup></td>
            <td>
              <a href="https://en.wikipedia.org/wiki/Mars_(planet)" class="button">
                Learn More
              </a>
            </td>
          </tr>
        </tbody>
      </table>
      ...
      

      This table HTML creates a table called “Terrestrial Planets Statistics” by putting that name in the <caption> element, a necessary component of screen-reader accessible tables. Then the HTML creates a five-column table consisting of a header row and four data rows.

      Next, to add some visual styles to the table, open styles.css in your text editor. You will create a visual style that makes the caption like a header for the table. The table header row will become more distinct with a dark background, and you will create a zebra stripe effect with alternating background colors on the data rows. The highlighted CSS in the following code block demonstrates how these styles are written:

      styles.css

      ...
      table {
        border-collapse: collapse;
        width: 100%;
        margin: 3rem 0;
      }
      
      caption {
        font-size: 1.5rem;
        font-weight: 700;
        color: hsl(215, 25%, 25%);
        text-align: left;
        margin-bottom: 0.5em;
      }
      
      tr {
        text-align: center;
      }
      
      thead > tr {
        color: hsl(215, 25%, 100%);
        background-color: hsl(215, 80%, 20%);
      }
      
      tbody > tr:nth-child(even) {
        background-color: hsl(215, 50%, 93%);
      }
      
      tbody th {
        font-size: 1.125rem;
      }
      
      td, th {
        padding: 0.5rem;
      }
      

      Save your changes to styles.css and open index.html in your web browser. The table is styled with clear data and alignment, as shown in the following image:

      Table grid of data containing information about the four terrestrial planets.

      Open your local version of index.html on a smart phone, or scale your browser’s window down to about the size of a smart phone. The table will eventually start going off screen and will only be viewable by scrolling horizontally, as demonstrated in the following image:

      A phone containing a table going off screen, cutting off informations.

      This is a situation where changing the display value of the table elements can help provide a better viewing experience for those on smaller screens.

      Return to styles.css in your text editor and create a media query set to a max-width of 60rem. Normally, you would use min-width instead of max-width in your media queries to follow a mobile first design flow. However, since you will only change the style on small screens and then return to the browser default at a given screen size, in this example situation max-width requires the least work. Inside the media query, create a group combinator consisting of table, caption, thead, tbody, tr, th, and td. Then set the display property to block, as highlighted in the following code block:

      styles.css

      @media (max-width: 60rem) {
        table,
        caption,
        thead,
        tbody,
        tr,
        th,
        td {
          display: block;
        }
      }
      

      Save your changes to styles.css and return to index.html on your smartphone or in a small-size browser window. All the contents of the table are now stacked in one large column, with each row’s contents grouped together. The following image shows how this is rendered on a mobile phone:

      Contents of a table in a vertical stack.

      This change to the table’s display value creates two issues. The first is that the browser no longer recognizes the table as a table, and therefore will not be read to a screen reader as a table. The second is that some of the contents and styles are now not providing useful information. For starters, the table headers no longer provide visual connection to the data types. Secondly, the zebra stripes don’t provide as much information in this scenario.

      Return to styles.css in your text editor. First, remove thead from the group combinator. Next, create a new selector for the thead element and give it a display property set to a value of none. The display: none value completely removes an element visually from rendering in the browser. It is important to know that the none value also removes the element from the screen reader DOM, so the element is hidden from all users. The highlighted CSS in the following code block shows how this is set up:

      styles.css

      @media (max-width: 60rem) {
        table,
        caption,
        tbody,
        tr,
        th,
        td {
          display: block;
        }
      
        thead {
          display: none;
        }
      }
      

      Next, to begin addressing the style changes, start by adding a text-align property to the large group combinator with a value of left. Next, duplicate the selector used for the zebra stripes, tbody> tr:nth-child(even), and set the background-color to transparent. This will remove the zebra stripe effect on screens and windows smaller than 60rem, or 960px, wide. Then, make the Learn More button work as a full-width button on small screens. Create a table .button descendant selector with the display property set to block, which will cause the button to fill the width of the container. The highlighted CSS in the following code block illustrates how this looks:

      styles.css

      @media (max-width: 60rem) {
        table,
        caption,
        tbody,
        tr,
        th,
        td {
          display: block;
          text-align: left;
        }
      
        thead {
          display: none;
        }
      
        tbody > tr:nth-child(even) {
          background-color: transparent;
        }
      
        table .button {
          display: block;
        }
      }
      

      Save your changes to styles.css in your text editor and then refresh index.html in your browser. On small-screen devices, the content of the tables are now all left-aligned with the button spanning the width of the content. The following image shows how this is rendered in Safari on a mobile phone:

      A series of bold heading text with data information and a button for each group.

      In this section, you converted a table to a block element to make it more visually usable when the screen or browser window small. In the last section, you will improve the accessibility of the table both for sighted users and those using screen readers.

      Adding Small-Screen Context Elements

      Now that you have changed the display values for the table elements on a small screen, you can add some enhancements to make this view as useful as the large screen version. You will add some HTML that will help make the information more understandable on small screens. Then you will provide styling specifically for the small screen experience of the table information.

      To begin, open index.html in your text editor. To provide the table’s contextual information lost by hiding the thead element, you will add that header value to each cell inside a <span> element. For example, you will add <span>Radius: </span> before the value in the column containing the Radius information for the planet in each <td> element. Additionally, each <span> element will have a class attribute set to a value of label, so these elements can be quickly styled. The highlighted HTML in the following code block shows how to write the markup:

      index.html

      ...
        <tbody>
          <tr>
            <th>Mercury</th>
            <td><span class="label">Radius: </span>2,439.7 km</td>
            <td><span class="label">Moons: </span>0</td>
            <td><span class="label">Gravity: </span>3.7 m/s<sup>2</sup></td>
            <td>
              <a href="https://en.wikipedia.org/wiki/Mercury_(planet)" class="button">
                Learn More
              </a>
            </td>
          </tr>
          <tr>
            <th>Venus</th>
            <td><span class="label">Radius: </span>6,051.8 km</td>
            <td><span class="label">Moons: </span>0</td>
            <td><span class="label">Gravity: </span>8.87 m/s<sup>2</sup></td>
            <td>
              <a href="https://en.wikipedia.org/wiki/Venus_(planet)" class="button">
                Learn More
              </a>
            </td>
          </tr>
          <tr>
            <th>Earth</th>
            <td><span class="label">Radius: </span>6,371.0 km</td>
            <td><span class="label">Moons: </span>1</td>
            <td><span class="label">Gravity: </span>9.80665 m/s<sup>2</sup></td>
            <td>
              <a href="https://en.wikipedia.org/wiki/Earth_(planet)" class="button">
                Learn More
              </a>
            </td>
          </tr>
          <tr>
            <th>Mars</th>
            <td><span class="label">Radius: </span>3,389.5 km</td>
            <td><span class="label">Moons: </span>2</td>
            <td><span class="label">Gravity: </span>3.72076 m/s<sup>2</sup></td>
            <td>
              <a href="https://en.wikipedia.org/wiki/Mars_(planet)" class="button">
                Learn More
              </a>
            </td>
          </tr>
        </tbody>
      ...
      

      Save your changes to index.html and return to your browser to examine the small-screen view. The contextual information around what each data point means is now visually recognizable. The following image shows how this will render in the browser:

      A series of bold heading text with contextual data information and a button for each group.

      Next, return to styles.css in your text editor. These labels will be present on larger screens when they are no longer necessary, so they will need some styling to fix this issue. Due to the max-width media query approach, this means that the default styles for .label outside the query need to be set to display: none in order to hide the content on large screens. Then inside the media query, create a .label selector with a display property set to inline, since it should be in the content flow containing the value. To create a visual separation between the label and data point, add a font-weight property set to 700. The highlighted CSS in the following code block demonstrates how and where to apply these additions:

      styles.css

      ...
      td, th {
        padding: 0.5rem;
      }
      
      .label {
        display: none;
      }
      
      @media (max-width: 60rem) {
        ...
        .label {
          display: inline;
          font-weight: 700;
        }
      }
      

      Save your changes to styles.css and once again return to your browser and refresh index.html. The browser will render the labels as inline content that is bold, as shown in the following image:

      A series of bold heading text with bold contextual labels and data information and a button for each group.

      While still in your web browser on a large screen, expand the window out until the table returns to the tabular style. The labels are now hidden providing distinctive visual and accessible information for each scenario. The following image shows how the large screen version of the table is now rendered:

      Table grid of data containing information about the four terrestrial planets.

      Finally, you will provide additional styling for each table row that will make them appear as their own little tables.

      Open styles.css in your text editor. Inside the media query, add a tbody th descendant selector and add the color properties and values from the thead > tr selector. This will give the same dark blue background and near-white text color for each planet name. Then, add a border-radius property set to 0.5rem 0.5rem 0 0 to create a rounded top to the heading. The highlighted CSS of the following code block shows how to style the planet name:

      stlyes.css

      ...
      @media (max-width: 60rem) {
        ...
        .label {
          display: inline;
          font-weight: 700;
        }
      
        tbody th {
          color: hsl(215, 25%, 100%);
          background-color: hsl(215, 80%, 20%);
          border-radius: 0.5rem 0.5rem 0 0;
        }
      }
      

      Next, you will add some definition to the datasets and give some spacing between each grouping. First, create a tbody > tr selector inside the media query with a border property set to 1px solid hsl(215, 80%, 20%). Then add a border-radius property with a value of 0.5rem, which will round the corner of all sides of the container. Lastly, create a tbody > tr + tr adjacent sibling combinator, with a margin-top property set to 1rem, which will give space between each group of data. The highlighted CSS in the following code block demonstrates how this is written:

      stlyes.css

      ...
      @media (max-width: 60rem) {
        ...
        tbody th {
          color: hsl(215, 25%, 100%);
          background-color: hsl(215, 80%, 20%);
          border-radius: 0.5rem 0.5rem 0 0;
        }
      
        tbody > tr {
          border: 1px solid hsl(215, 80%, 20%);
          border-radius: 0.5rem;
        }
      
        tbody > tr + tr {
          margin-top: 1rem;
        }
      }
      

      Finally, you will add in a zebra stripe effect specifically for each td element. This is done by creating a td:nth-child(even) pseudo-class selector. Then use the same background-color property and value from before, as highlighted in the following code block:

      stlyes.css

      ...
      @media (max-width: 60rem) {
        ...
        tbody > tr + tr {
          margin-top: 1rem;
        }
      
        td:nth-child(even) {
          background-color: hsl(215, 50%, 93%);
        }
      }
      

      Save your changes to styles.css and open index.html on a small-width browser or smartphone. Each row from the table will now appear as though it were a table with a header, data points, and a button to learn more. The following image shows how this is rendered in on a smartphone browser:

      Groups of data blocks, with the header in white on a dark background, and data points in alternating rows of light blue and white background.

      In this last section, you used the display property to show and hide pertinent information that was contextual to the viewing scenario of a small-screen device. You also provided styling to the small-screen table to make it more accessible and usable.

      Conclusion

      There are many possibilities when working with the display property. In this tutorial, you learned about the default values of block and inline. You changed an <a> element to inline-block, which gave it a special combination of both block and inline. You then changed all the elements of a <table> to be block on a small screen and set them to return to their default table display values on a large screen. Lastly, you used the none value to hide content when and where necessary to users of all abilities. The display property is a powerful feature and has even more values available to further manipulate how the box model functions and affects 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

      Cleaner Laravel Controllers with Route Model Binding


      Introduction

      Laravel as a framework either for building websites or a container to build APIs (lumen) has evolved as a developer’s framework of choice. Laravel comes with a lot of growing features – take for example Laravel’s events. Events in Laravel used to be a simple pub-sub library, but now Laravel events can broadcast all the way to the client and allows us to create real-time apps.

      But that’s beside the point, today’s celebrity is Laravel’s route model binding.

      What is Route Model Binding

      Route model binding in Laravel provides a mechanism to inject a model instance into your routes. Still not clear on the meaning, here is an example. Say we want to get a post from the database, we could do something like this:

      ...
      // the route parameter is the id of the post
      // for example http://example.com/posts/53
      Route::get('posts/{id}', function ($id) {
      
        // we have to find the post using the $id
        $post = Post::find($id);
      
        // if there is no post, 404
        if (!$post) return abort(404);
      
        // return the view and the post
        return view('post.show', compact('post'));
      });
      ...
      

      We could further go on to simplify this method into

      ...
      // the route parameter is the id of the post
      // for example http://awesome.dev/posts/53
      Route::get('posts/{id}', function ($id) {
      
        // find the post or 404 if not found
        $post = Post::findOrFail($id);
      
        // return the view and the post
        return view('post.show', compact('post'));
      });
      ...
      

      But route model binding helps us get rid of extra keystrokes by simplifying both instances above into

      ...
      // by using $post, we can inject the Post object
      Route::get('posts/{post}', function ($post) {
      
        // we now have access to the $post object! no code necessary
      
        // return the view and the post
        return view('post.show', compact('post'));
      });
      ...
      

      This is made possible by telling Laravel to inject a Post model into any route controller that has a {post} parameter attached to it.

      Laravel currently supports two types of route model bindings. We have:

      • Implicit model binding
      • explicit model binding

      Note: The example of route model binding listed above is explicit.

      Implicit Model Binding

      While we’ve seen explicit model binding, here’s an example of implicit model binding now:

      Route::get('posts/{post}', function (AppPost $post) {
        // be awesome. enjoy having the $post object
      });
      

      Laravel is smart enough to know that since a Post model is being injected into the controller closure, it should get the id parameter from the route and get the details for the user.

      Accessing a post will still be done using http://awesome.example.com/posts/24.

      Changing the Model’s Route Key

      If you would like the implicit model binding to use a database column other than id when retrieving models, you may override the getRouteKeyName method on your Eloquent model.

      For instance, if we wanted to use the slug instead of the id, we could do the following:

      class Post extends Model {
        public function getRouteKeyName() {
          return 'slug';
        }
      }
      

      Then we could access our route using http://awesome.example.com/posts/my-post-slug instead of http://awesome.example.com/posts/24.

      Explicit Model Binding

      Just like the name implies, you have to explicitly tell Laravel you want it to bind a url parameter to a particular model. There are two ways to do this, we could bind a parameter to a model using the provided Route facade or carry out this binding in app/Providers/RouteServiceProvider.php (I prefer this method).

      Using the Route Facade

      Using the Route facade to bind a parameter to a model, we can do something like this:

      Route::bind('post', 'AppPost');
      

      We could also give our binding more meaning, for example, what if we want a post only if is a draft? For that, we could change the second parameter of the Route::bind to a closure which takes the route parameter as its value.

      Route::bind('post', function ($value) {
        return AppPost::find($value)->where('status', '=', 'published')->first();
      });
      

      Using the RouteServiceProvider

      The only difference between using the Route facade and RouteServiceProvider class is that – registering your bindings is done in the boot method of the RouteServiceProvider class (location is app/Providers directory) and the bind method is called on the $router object injected into the method. Quick example

      public function boot(Router $router)
      {
        parent::boot($router);
      
        $router->bind('post', function ($value) {
          return AppPost::find($value)->where('status', '=', 'published')->first();
        });
      }
      

      Custom Exceptions for Route Model Binding

      I build a lot of APIs, so custom exceptions for route model bindings are actually more useful for people like me. Laravel provides an easy way for us to do this. Still in the boot method of the RouteServiceProvider class, call the model method on the $router object.

      The model method takes three arguments, the arguments are similar to that of the bind method, with a new addition the third argument which is a closure that throws the new exception.

      $router->model($routeParameter, $modelToBind, function () {
        throw new NotFoundHTTPException;
      });
      

      Conclusion

      You can read more about route model binding in the documentation.

      Hopefully this small, but neat feature can save you a few lines of code in your projects and make your controllers that much cleaner.



      Source link

      How To Deploy a Pre-Trained Question and Answer TensorFlow.js Model on App Platform


      The author selected Code 2040 to receive a donation as part of the Write for DOnations program.

      Introduction

      As the field of machine learning (ML) grows, so does the list of environments for using this technology. One of these environments is the web browser, and in recent years, there has been a surge in data-related frameworks targeting web-based machine learning models. An example of these frameworks is TensorFlow.js, TensorFlow’s JavaScript counterpart library for training, executing, and deploying machine learning models in the browser. In an attempt to make TensorFlow.js accessible to developers with limited or no ML experience, the library comes with several pre-trained models that work out of the box.

      A pre-trained machine learning model is ready-to-use machine learning you don’t have to train. TensorFlow.js includes 14 that suit a variety of use cases. For example, there is an image classifying model for identifying common objects and a body segmentation model for identifying body parts. The principal convenience of these models is that, as the name states, you don’t have to train them. Instead, you load them in your application. Besides their ease of use and pre-trained nature, these are curated models—they are accurate and fast, sometimes trained by the algorithms’ authors and optimized for the web browser.

      In this tutorial, you will create a web application that serves a Question and Answer (QnA) pre-trained model using TensorFlow.js. The model you will deploy is a Bidirectional Encoder Representations from Transformers (BERT) model that uses a passage and a question as the input, and tries to answer the question from the passage.

      You will deploy the app in DigitalOcean’s App Platform, a managed solution for building, deploying, and scaling applications within a few clicks from sources such as GitHub. The app you will create consists of a static page with two input fields, one for the passage and one for the question. In the end, you will have a written and deployed—from GitHub—a Question and Answer application using one of TensorFlow.js’ pre-trained models and DigitalOcean’s App Platform.

      Prerequisites

      To complete this tutorial, you will need:

      Step 1 — Creating the App’s Interface and Importing the Required Libraries

      In this step, you will write the app’s HTML code, which will define its interface and import the libraries for the app. The first of these libraries is TensorFlow.js, and instead of installing the package locally, you will load it from a content delivery network or CDN. A CDN is a network of servers spanning multiple locations that store content they provide to the internet. This content includes JavaScript files, such as the TensorFlow.js library, and loading it from a CDN saves you from packing them in your application. Similarly, you will import the library containing the Question and Answer model. In the next step, you will write the app’s JavaScript, which uses the model to answer a given question.

      In this tutorial, you will structure an app that will look like this:

      The app

      The app has five major elements:

      • A button that loads a pre-defined passage you can use to test the app.
      • An input text field for a passage (if you choose to write or copy your own).
      • An input text field for the question.
      • A button that triggers the prediction that answers the question.
      • An area to display the model’s output beneath the Answer! button (currently blank white space).

      Start by creating a new directory named tfjs-qna-do at your preferred location. In this directory, using a text editor of your choice, create a new HTML file named index.html and paste in the following code:

      index.html

      <!DOCTYPE html>
      <html lang="en-US">
      
      <head>
          <meta charset="utf-8" />
          <!-- Load TensorFlow.js -->
          <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
          <!-- Load the QnA model -->
          <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/qna"></script>
          <link href="./style.css" rel="stylesheet">
      </head>
      
      <body>
          <div class="main-centered-container">
              <h1>TensorFlow.js Pre-trained "QnA" BERT model</h1>
              <h3 class="header-border">Introduction</h3>
              <p>This application hosts TensorFlow.js' pre-trained Question and Answer model, and it attempts to answer the question
              using a given passage. To use it, write a passage (any!) in the input area below and a question. Then, click the
              "answer!" button to answer the question using the given passage as a reference. You could also click the test
              button to load a pre-defined input text.</p>
      
              <h4>Try the test passage!</h4>
              <div id='test-buttons'></div>
      
              <div>
                  <h4>Enter the model's input passage here</h4>
                  <textarea id='input-text' rows="20" cols="100" placeholder="Write the input text..."></textarea>
              </div>
      
              <div>
                  <h4>Enter the question to ask</h4>
                  <textarea id='question' rows="5" cols="100" placeholder="Write the input text..."></textarea>
              </div>
              <h4>Click to answer the question</h4>
              <div id="answer-button"></div>
              <h4>The model's answers</h4>
              <div id='answer'></div>
      
              <script src="./index.js"></script>
      
      
          </div>
      </body>
      
      </html>
      

      Here’s how that HTML breaks down:

      • The initial <html> tag has the <head> tag that’s used for defining metadata, styles, and loading scripts. Its first element is <meta>, and here you will set the page’s charset encoding to utf-8. After it, there are two <script> tags for loading both TensorFlow.js and the Question and Answer model from a CDN.
      • Following the two <script> tags, there’s a <link> tag that loads a CSS file (which you will create next).
      • Next, there’s the HTML’s <body>—the document’s content. Inside of it, there’s a <div> tag of class main-centered-container containing the page’s elements. The first is a <h1> header with the application title and a smaller <h3> header, followed by a brief introduction explaining how it works.
      • Under the introduction, there’s a <h4> header and a <div> where you will append buttons that populate the passage input text field with sample text.
      • Then, there are the app’s input fields: one for the passage (what you want the model to read) and one for the question (what you want the model to answer). If you wish to resize them, change the rows and cols attributes.
      • After the text fields, there’s a <div> with id button where you will later append a button that, upon clicking, reads the text fields’ text and uses them as an input to the model.
      • Last, there is a <div> with id answer that’s used to display the model’s output and a <script> tag to include the JavaScript code you will write in the following section.

      Next, you’ll add CSS to the project. In the same directory where you added the index.html file, create a new file named style.css and add the following code:

      style.css

      body {
        margin: 50px 0;
        padding: 0;
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial;
      }
      
      button {
        margin: 10px 10px;
        font-size: 100%;
      }
      
      p {
        line-height: 1.8;
      }
      
      .main-centered-container {
        padding: 60px;
        display: flex;
        flex-direction: column;
        margin: 0 auto;
        max-width: 960px;
      }
      
      .header-border {
        border: solid #d0d0d0;
        border-width: 0 0 1px;
        padding: 0 0 5px;
      }
      

      This CSS adds style to three HTML elements: body, buttons, and paragraphs (<p>). To body, it adds a margin, padding, and changes the default font. To button, it adds margin and increases the font size. To paragraph p, it modifies the line-height attribute. The CSS has a class main-centered-container that centers the content and another one, header-border, that adds a solid line to an element.

      In this step, you wrote the app’s HTML file. You imported the TensorFlow.js library and QnA model, and defined the elements you will use later to add the passage and the question you want to answer. In the following step, you will write the JavaScript code that reads the elements and triggers the predictions.

      Step 2 — Predicting with the Pre-Trained Model

      In this section, you will implement the web app’s JavaScript code that reads the app’s input fields, makes a prediction, and writes the predicted answers in HTML. You will do it in one function that’s triggered when you click the “answer” button. Once clicked, it will reference both input fields to get their values, use them as inputs to the model, and write its output in the <div> with id output you defined in Step 1. Then, you will run the app locally to test it before adding it to GitHub.

      In the project’s directory tfjs-qna-do/, create a new file named index.js, and declare the following variables:

      index.js

      let model;
      
      // The text field containing the input text
      let inputText;
      
      // The text field containing the question
      let questionText;
      
      // The div where we will write the model's answer
      let answersOutput;
      

      The first of the variables, model, is where you will store the QnA model; inputText and questionText are references to the input and question text fields; answersOutput is a reference to the output <div>.

      In addition to these variables, you will need a constant for storing the sample text you will use to test the app. We will use the Wikipedia article on DigitalOcean as a sample passage. Based on this passage, you could ask the model questions like “Where is DigitalOcean headquartered?” and hopefully, it will output “New York”.

      Copy this block into your index.js file:

      index.js

      // Sample passage from Wikipedia.
      const doText = `DigitalOcean, Inc. is an American cloud infrastructure provider[2] headquartered in New York City with data centers worldwide.[3] 
      DigitalOcean provides developers cloud services that help to deploy and scale applications that run simultaneously on multiple computers.
      DigitalOcean also runs Hacktoberfest which is a month-long celebration (October 1-31) of open source software run in partnership with GitHub and Twilio.
      `;
      

      Now, you will define the app’s functions, starting with createButton(). This function creates a button and appends it to an HTML element:

      index.js

      function createButton(innerText, id, listener, selector, disabled = false) {
        const btn = document.createElement('BUTTON');
        btn.innerText = innerText;
        btn.id = id;
        btn.disabled = disabled;
      
        btn.addEventListener('click', listener);
        document.querySelector(selector).appendChild(btn);
      }
      

      createButton() is a function that creates the app’s two buttons; since all the buttons work similarly, this function avoids repeating code. The function has five parameters:

      • innerText: the button’s text.
      • id: the button’s id.
      • listener: a callback function that’s executed when the user clicks the button.
      • selector: the <div> element where you will append the button.
      • disabled: a boolean value to disable or enable the button. This parameter’s default value is false.

      createButton() starts by creating an instance of a button and assigns it to the variable btn. Then, it sets the button’s innerText, id, and disabled attributes. The button uses a click event listener that executes a callback function whenever you click it. The function’s last line appends the button to the <div> element specified in the selector parameter.

      Next, you will create a new function named setupButtons() that calls createButton() two times to create the app’s buttons. Begin by creating the app’s Answer! button:

      index.js

      function setupButtons() {
        // Button to predict
        createButton('Answer!', 'answer-btn',
          () => {
            model.findAnswers(questionText.value, inputText.value).then((answers) => {
              // Write the answers to the output div as an unordered list.
              // It uses map create a new list of the answers while adding the list tags.
              // Then, we use join to concatenate the answers as an array with a line break
              // between answers.
              const answersList = answers.map((answer) => `<li>${answer.text} (confidence: ${answer.score})</li>`)
                .join('<br>');
      
              answersOutput.innerHTML = `<ul>${answersList}</ul>`;
            }).catch((e) => console.log(e));
          }, '#answer-button', true);
      }
      

      The first button the function creates is the one that triggers the predictions. Its first two arguments, innerText and id, are the button’s text and the identifier you want to assign to the button. The third argument is the listener’s callback (explained below). The fourth argument, selector, is the id of the <div> where you want to add the button (#answer-button), and the fifth argument, disabled, is set to true, which disables the button (to avoid predicting before the app loads the model).

      The listener’s callback is a function that’s executed once you click the Answer! button. Once clicked, the callback function first calls the pre-trained model’s function findAnswers(). (For more about the findAnswers() function, see the product documentation). findAnswers() uses as arguments the input passage (read from questionText) and the question (read from inputText). It returns the model’s output in an array that looks as follows:

      Model's output

      [ { "text": "New York City", "score": 19.08431625366211, "startIndex": 84, "endIndex": 97 }, { "text": "in New York City", "score": 8.737937569618225, "startIndex": 81, "endIndex": 97 }, { "text": "New York", "score": 7.998648166656494, "startIndex": 84, "endIndex": 92 }, { "text": "York City", "score": 7.5290607213974, "startIndex": 88, "endIndex": 97 }, { "text": "headquartered in New York City", "score": 6.888534069061279, "startIndex": 67, "endIndex": 97 } ]

      Each of the array’s elements is an object of four attributes:

      • text: the answer.
      • score: the model confidence level.
      • startIndex: the index of the passage’s first character that answers the question.
      • endIndex: the index of the answer’s last characters.

      Instead of displaying the output as the model returns it, the callback uses a map() function that creates a new array containing the model’s answers and scores while adding the list <li> HTML tags. Then, it joins the array’s elements with a <br> (line break) between answers and assigns the result to the answer <div> to display them as a list.

      Next, add a second call to createButton(). Add the highlighted portion to the setupButtons function beneath the first createButton:

      index.js

      function setupButtons() {
        // Button to predict
        createButton('Answer!', 'answer-btn',
          () => {
            model.findAnswers(questionText.value, inputText.value).then((answers) => {
              // Write the answers to the output div as an unordered list.
              // It uses map create a new list of the answers while adding the list tags.
              // Then, we use join to concatenate the answers as an array with a line break
              // between answers.
              const answersList = answers.map((answer) => `<li>${answer.text} (confidence: ${answer.score})</li>`)
                .join('<br>');
      
              answersOutput.innerHTML = `<ul>${answersList}</ul>`;
            }).catch((e) => console.log(e));
          }, '#answer-button', true);
      
        createButton('DigitalOcean', 'test-case-do-btn',
          () => {
           document.getElementById('input-text').value = doText;
          }, '#test-buttons', false);
      }
      

      This new call appends to the test-buttons <div> the button that loads the DigitalOcean sample text you defined earlier in the variable doText. The function’s first argument is the label for the button (DigitalOcean), the second argument is the id, the third is the listener’s callback that writes in the passage input text area the value of the doText variable, the fourth is the selector, and the last is a false value (to avoid disabling the button).

      Next, you will create a function, named init(), that calls the other functions:

      index.js

      async function init() {
        setupButtons();
        answersOutput = document.getElementById('answer');
        inputText = document.getElementById('input-text');
        questionText = document.getElementById('question');
      
        model = await qna.load();
        document.getElementById('answer-btn').disabled = false;
      }
      

      init() starts by calling setupButtons(). Then, it assigns some of the app’s HTML elements to the variables you defined at the top of the script. Next, it loads the QnA model and changes to false the disabled attribute of the answer (answer-btn) button.

      Last, call init():

      index.js

      init();
      

      You have finished the app. To test it, open your web browser and write the project’s directory absolute path with /index.html appended to it in the address bar. You could also open your file manager application (such as Finder on Mac) and click on “index.html” to open the web application. In this case, the address would look like your_filepath/tfjs-qna-do/index.html.

      To find the absolute path, go to the terminal and execute the following command from the project’s directory:

      Its output will look like this:

      Output

      /Users/your_filepath/tfjs-qna-do

      After launching the app, you will need to wait a few seconds while it downloads and loads the model. You will know it’s ready when the app enables the Answer! button. Then, you could either use the test passage button (DigitalOcean) or write your own passage, and then input a question.

      To test the app, click the “DigitalOcean” button. In the passage input area, you will see the sample text about DigitalOcean. In the question input area, write “Where is DigitalOcean headquartered?” From the passage, we can see the answer is “New York”. But will the model say the same? Click Answer! to find out.

      The output should look similar to this:

      Model's answers to "where is DO headquartered?"

      Correct! Although there are slight differences, four of the five answers say that DigitalOcean’s headquarters are in New York City.

      In this step, you completed and tested the web application. The JavaScript code you wrote reads the input passage and question and uses it as an input to the QnA model to answer the question. Next, you will add the code to GitHub.

      Step 3 — Pushing the App to GitHub

      In this section, you will add the web application to a GitHub repository. Later, you will connect the repository to DigitalOcean’s App Platform and deploy the app.

      Start by logging in to GitHub. From its main page, click the green button under your name or the plus sign on the screen’s upper right corner to create a new repository.

      Click to create a repository

      Click to create a repository

      Either choice takes you to the Create a new repository screen. In the Repository name field (after your username), name the repository tfjs-qna-do. Select its privacy setting, and click Create repository to create it.

      Create the repository

      Open a terminal and go to the project’s directory tfjs-qna-do/. There, execute the following command to create a new local Git repository:

      Next, stage the files you want to track with Git, which in this case, is everything in the directory:

      And commit them:

      • git commit -m "initial version of the app"

      Rename the repository’s principal branch to main:

      Then link your local repository with the remote one on GitHub:

      • git remote add origin git@github.com:your-github-username/tfjs-qna-do.git

      Last, push the local codebase to the remote repository:

      It will ask you to enter your GitHub credentials if this is the first time you are pushing code to it.

      Once you have pushed the code, return to the GitHub repository and refresh the page. You should see your code.

      The code in the repo

      In this step, you have pushed your web app’s code to a remote GitHub repository. Next, you will link this repository to your DigitalOcean account and deploy the app.

      Step 4 — Deploying the Web Application in DigitalOcean App Platform

      In this last section, you will deploy the Question and Answer app to DigitalOcean’s App Platform) from the GitHub repository created in Step 3.

      Start by logging into your DigitalOcean account. Once logged in, click the Create green button in the upper right corner and then on Apps; this takes you to the Create new app screen:

      Create a new DO App

      Here, choose GitHub as the source where the project resides.

      Choose the source

      If you haven’t linked your DigitalOcean account with GitHub, it will ask you to authorize DigitalOcean to access your GitHub. After doing so, select the repository you want to link: tfjs-qna-do.

      Link the repo

      Back on the App Platform window, select the app’s repository (tfjs-qna-do), the branch from where it will deploy the app (main), and check the Autodeploy code changes box; this option ensures that the application gets re-deployed every time you push code to the main branch.

      Choose the source (cont.)

      In the next screen, Configure your app, use the default configuration values. As an additional step, if you wish to change the web app’s HTTP requests route, from, for example, the default https://example.ondigitalocean.app/tfjs-qna-do, to https://example.ondigitalocean.app/my-custom-route, click on Edit under HTTP Routes and write my-custom-route in the ROUTES input.

      Configure the app

      Next, you will name the site. Again, you could leave the default tfjs-qna-do name or replace it with another one.

      Name the site

      Clicking Next will take you to the last screen, Finalize and launch, where you will select the app’s pricing tier. Since the app is a static webpage, App Platform will automatically select the free Starter plan. Last, click the Launch Starter App button to build and deploy the application.

      Finalize and launch

      While the app is deployed, you will see a screen similar to this:

      Deploying app

      And once deployed, you will see:

      Deployed

      To access the app, click on the app’s URL to access your app, which is now deployed in the cloud.

      Deployed app

      Conclusion

      As the field of machine learning expands, so do its use cases alongside the environments and platforms it reaches – including the web browser.

      In this tutorial, you have built and deployed a web application that uses a TensorFlow.js pre-trained model. Your Question and Answer web app takes as input a passage along with a question and uses a pre-trained BERT model to answer the question according to the passage. After developing the app, you linked your GitHub account with DigitalOcean and deployed the application in App Platform without needing additional code.

      As future work, you could trigger the app’s automatic deployment by adding a change to it and pushing it to GitHub. You could also add a new test passage and format the answer’s output as a table to improve its readability.

      For more information about TensorFlow.js, refer to its official documentation.



      Source link