The author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program.
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.
color
properties in CSS. See How To Use Color Values with CSS to learn more.background
properties. Check out How To Apply Background Styles to HTML Elements with CSS to gain experience creating gradient backgrounds.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.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:
<!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="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:
<!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:
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:
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:
- mkdir images
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:
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:
...
.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:
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.
border
PropertyThe 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:
...
.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:
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:
...
.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:
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
:
...
.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:
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:
...
.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:
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.
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:
...
.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:
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
:
...
.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:
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:
...
.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:
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:
...
.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:
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.
text-shadow
PropertyApplying 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:
...
.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:
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:
...
.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:
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.
box-shadow
to ElementsJust 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:
...
.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:
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:
...
.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:
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:
...
.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:
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:
...
.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:
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:
...
.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:
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
.
outline
PropertyThe 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:
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:
...
.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:
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:
...
.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:
...
.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:
...
.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:
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.
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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Cascading Style Sheets (CSS) is the styling language of the web, and is used to design and control the visual representation of Hypertext Markup Language (HTML) on a web page. With CSS, you can manage everything from font to layout to animations on your web page. This series will lead the reader through CSS exercises that demonstrate the building blocks of the language and the fundamental design principles needed to make a user-friendly web site.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!