Section
Web page content goes here...
Welcome! I built this HTML5 Tutorial Page to help new web developers and designers around the world learn how to code web pages the right way! After seeing so many developers struggling with basic HTML and CSS over the years, I decided to create this comprehensive HTML5 tutorial to help everyone. I hope you will use it to learn HTML or improve upon your own HTML coding skills.
This HTML5 tutorial has all the code needed to start building your web pages quickly. As such, it is less of an introduction to markup languages and web development, and more of a "crib sheet" or quick reference page for HTML5. In that sense, you will find this page is a very powerful tool for cutting-and-pasting markup directly into your own pages without having to cobble code together. You can therefore skip to various sections in this page and copy the code directly into your own without having to read through the complete tutorial. I designed it to work this way so developers could skip all the other incomplete tutorials online and use mine as a complete codebase for all your web projects.
This web tutorial consists of two main sections: An HTML5 listing of all the elements with my recommended attributes, and a special "Best Practices" section which lists lots of tricks and traps I have discovered in HTML5 and CSS that will help you become a better coder. Both sections have code you can copy directly into your web projects. They are complete with all the right markup, attributes, and code based on over 20+ years of working with HTML.
Why did I build this HTML5 tutorial, when there is so much material online about HTML5 and how to get started building web pages? Sadly, most of the training and tutorials you will find on the World Wide Web for HTML and CSS are not complete and missing most of the required tricks and techniques needed to code in those languages. To account for that lack of learning, many young developers then turn to 3rd party scripted products that they hope will solve all their web development problems. But nearly all these web development products fail because they do not adequately address all the various issues in web browsers, past and present. In implementing these modern software solutions, many development groups are then dependent on outside technology to solve problems instead of learning to code in HTML and CSS. I have seen this problem first hand at many corporations I have worked for. They then rely on developers who know the tools but not the code! They are not experienced enough in markup or style sheet languages to know how to address all the bugs and issues in browsers of the past, much less those built today specifically for HTML5.
The fact is, there is so much knowledge and expertise needed in building solid HTML/CSS web applications today that relying on these 3rd party products, then failing to even learn basic HTML and CSS, means you are "half a web developer". For that reason, I decided it was critical I preserve for posterity this wealth of HTML5 coding information for the web development community so that they will not have to rely on products or JavaScripted solutions to build web pages ever again. The fact is, you should always learn coding from experienced web developers. Failing to learn from the past and from older developers means most new developers today will stumble and have to "rediscover" the same solutions after years of coding. The fact is, you MUST learn how to code HTML and CSS yourself before you can rely on these poorly written products. And you can only do that learning from others. Anything written by Mankind will always have flaws. The web browsers written by people today, and in the past, are FULL of bugs. Web browsers will always be "buggy". You just need to know the tricks to fix the bugs in your HTML so your web pages are parsed correctly and look great across many user agents. You just need to have the right code to bypass and fix blunders and errors built into modern web browsers today.
Over the years, using old and new web browsers, I have found solutions to nearly all the bugs found online. I have written CSS "hacks", and I have perfected my HTML markup so it looks and runs fast in nearly every web browser ever made. I felt it was time to gather all this knowledge here in one tutorial and share it with the world. Learning from the past, as well as building on the future, will make you a master at just about anything. With experience combined with cutting-edge technology, you can challenge the future with confidence. But learning anything takes mentoring and learning from others. It is like working on a car. You have to know the tricks, first, from a master mechanic, right? Technology is no different. Without knowledge of the tricks and tools, you are never going to be a master web developer. Having total knowledge of the latest and greatest web technologies means you have mastered only one layer of the technology. You also must learn the "old" practices, too. Too often new coders skip over lessons learned in the past and so are doomed to repeat them. In the end, learning old and new HTML techniques in parallel means you will come away from this lesson as an "all-knowing", experienced expert in HTML and CSS with solutions most of your peers will have completely missed. You can then climb into greatness, building from what others already mastered for you.
You can use the experienced advice in this one page to help "jumpstart" your career towards being a "great web coder" by simply learning what works in modern HTML5 browsers used today, but also learning what worked in the past. Combined, the two perfect the art of great HTML5 markup. But first you must learn from those who have passed through the gauntlet of web development and who have come out the other side with battle scars and wisdom to show for it. I am here to guide you on that journey.
This web page is about learning HTML5, right? But HTML often is not complete without CSS (Cascading Style Sheets). The two work closely together in delivering many types of Human-readable web pages and online documents. The CSS style sheet system that runs this page is itself a powerful and complete Universal CSS Framework that stands behind the design of most of the HTML elements you will see in this tutorial. My CSS system is unique because it not only "resets" all the elements so they look great across all known browsers, but is designed to support styling and markup used by web browsers the past 20+ years! As such, my CSS system is far superior to say, Bootstrap and its "reboot" sheet, which fails to address even a tiny percentage of past browser issues, or Modernizr which relies on thick-client JavaScript, or SASS which is yet another heavy pre-processing dependency. My simple cut-and-paste system solves all your cross-browser problems without any scripts whatsoever, and is designed to fix all the issues needed to support many types of browsers going back to 1995. Besides, I have been perfecting my CSS system for the past 20 years, long before any of these third party products were even built. My latest version of my Universal CSS package was recently updated for 2022 to not just support older user agents, but support the newest HTML5 web browsers used today. If you would like to use my CSS framework, there is a download section under "Best Practices" for both my HTML5 template and my CSS framework.
I hope you will use my HTML5 Tutorial, as well as my CSS knowledge, to improve your own skills so you can move forward, building on the past, towards greatness as a web developer. Happy coding!
- Mitchell Stokely, 2022
HTML5 is almost identical to the much older standards - HTML 3.2 / HTML 4.1 / XHTML 1.0 / XHTML 1.1 - all of which we implemented in websites from the 1990's up until 2008, when the first HTML5 recommendations were released for review. Now here in 2022, we have fully embraced HTML5, CSS3, and all the newer changes coming on the horizon that advance better website technologies. However, the basic design of HTML5 is the same as old HTML. There really is nothing truly cutting edge. The same goes for ECMAScript 6 and later. Its the same basic server-client model, same basic HTML and JavaScript parsers, same DOM, same single threaded browsers, and the same basic client-server model of information delivery. In addition, the past 20+ years have left a trail of older web technology and web pages that still run perfectly well and makes companies billions of dollars every year! But many older browsers remain behind that do not support HTML5, or which only partially support it. Without careful HTML design, you risk locking out millions of viewers from your website. As the HTML5's new "Living Standard" slowly evolves, it will continue to leave a trail of partial support in modern browsers used today.
Most of the elements in HTML5 look and work the same as those in say old HTML 4.1 and XHTML, with a few exceptions that are important. That fact has allowed experienced web developers to build on best practices gained from the past in the infancy of the World Wide Web when browser support for HTML and CSS was spotty. Without going into too much detail here, I will simply list below the core HTML5 elements supported that are universal to most past and present HTML recommendations, and talk about items unique to HTML5 you should be aware of. I will also list a few HTML5 elements that I do not recommend, either because few modern browsers support them, they rely on heavy JavaScripting to function, or the technology behind them fails.
Along with examples of solid HTML that works in old and new browsers, I have also added a full list of important attributes I recommend for those elements that allow your HTML markup to work at its peak and give browsers, search engines, and screen readers the necessary information they need get the most out of your website and its markup or scripting code. After this HTML5 elements list, I have added a "Best Practices" section with advice and code examples you should consider that build on 20 years of my personal web development experience. I will always include code in both sections which you can cut-and-paste into your web projects.
Keep in mind, this tutorial is quite a comprehensive list, but not totally exhaustive. It is likely there are details left out on some things you use I do not that are helpful in projects. They may not be that valuable in designing good cross-browser HTML, however. I have added all the newest elements and attributes, even some cutting edge stuff not yet talked about online. So this tutorial is cutting-edge. But the basic idea behind good HTML markup practices is first committing to using a "core" set of HTML and CSS code that works in old and new browsers, as well as solid design principles that are reliable across all web projects and which will stand the test of time. The "test of time" concept is what makes them great. Using the latest and greatest HTML and CSS technologies does not always benefit your projects simply because you leave so many other user's behind when you do. Anything added AFTER good HTML is icing on a cake you should have already carefully baked. JavaScript API's, for example, should always be layered over good HTML practices. They should ONLY be the icing. They can never be the cake or replace good HTML coding practices. Good HTML and CSS code is what works reliably in many browsers with few changes over years and years, as scripts and API's come and go. When JavaScript API's and frameworks are stripped away, or die from disuse over time (which nearly all will do), remember that after the smoke clears, good content written in good 'ol reliable HTML will always remain behind as it has been for almost 30 years on the Internet, now. Remember that fact, Luke, and the "HTML Force" will be with you!
Element | Name | HTML Example | |||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
<a> | anchor, link, hyperlink |
Anchor<a href="http://yourwebsite.com/" id="a1" title="View my Website" target="_blank" rel="noreferrer nofollow noopener" tabindex="0" aria-label="Your Website Link">A Hyperlink</a>
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
<abbr> | abbreviation |
Abbreviation<abbr title="World Health Organization">WHO</abbr>
The WHO was founded in 1948.
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
<address> | address |
Address
<address>
Visit us at:
My Business, Inc. Box 123 Some City, CA USA
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
<area> | area, map area |
Areasee <map>
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
<article> | article |
ArticleSee also <header>, <nav>, <main>, <footer>, <section>, and <aside>
<article id="article1" aria-label="Article1">Article 1</article>
Header
Main
Section
Footer
* A typical web page structure is shown above.
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
<aside> | aside |
AsideSee also <header>, <nav>, <main>, <footer>, <section>, and <article>
<aside id="complementary" role="complementary" aria-label="Aside">Aside</aside>
Header
Main
Section
Footer
* A typical web page structure is shown above.
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
<audio> | audio |
Audio
<figure aria-labelledby="myaudio">
(If your browser supports the audio element above you should see an audio control and hear a rain sound when playing.)
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
<base> | base url |
Base URL
<base href="/" target="_self" />
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
<bdo> | bidirectional override |
Bidirectional Override Text
Left-to-right - One type of text: <bdo dir="ltr">إيان</bdo>
Left-to-right - One type of text: إيان
Left-to-right - One type of text: John Smith Right-to-left - One type of text: إيان Right-to-left - One type of text: John Smith Left-to-right - Mixed types of text: John Smith and إيان Right-to-left - Mixed types of text: John Smith and إيان
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
<blockquote> | blockquote, long quotation |
Blockquote
I have decided to leave a quote below:
I have decided to leave a quote below:
Well done is better than well said.
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
<body> | body |
Bodysee <html>
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
<br> | break, line-break |
Break
This is an example of a line-break...<br />
This is an example of a line-break...
...I am now on a new line!
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
<button> | button |
Buttonsee <form> for more details using <button> in forms
A Button can "submit" Form Data
<form id="buttonform1" name="buttonform1" action="#" method="get" aria-label="Button Submit Form" title="Button Submit Form" autocomplete="off" autocapitalize="off" spellcheck="false">
A Button can send Name-Value Pairs Using the Same "name" Attribute
<form id="buttonform2" name="buttonform2" action="#" method="get">
A Button can also be a "Reset" Type, a Plain "Button" Type (no form submission), or "Disabled"
<form id="buttonform3" name="buttonform3" action="#" method="get">
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
<caption> | caption, table caption |
Caption
<table style="border: 1px solid black;border-collapse: collapse;border-spacing: 0px;padding: 10px;vertical-align: top;">
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
<canvas> | canvas |
Canvasalso see <svg>
<canvas id="canvas1" style="background-color:#ccc;border:1px solid #666;" width="100" height="100">
(The JavaScript used above in rendering this image is from the standard "Canvas Scripting API")
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
<cite> | citation |
Citation
<p>The <cite>Pieta</cite> is my favorite work by Michelangelo.</p>
The Pieta is my favorite work by Michelangelo.
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
<code> | code, computer code |
Code
<code>
<p>Here is my sample paragraph using HTML with the 'code' element</p>
My Recommendations:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
header 1 | header 2 | header 3 |
---|---|---|
body 1 | body 2 | body 3 |
footer 1 | footer 2 | footer 3 |
td:nth-child(3){...}
) on table cells can be used more effectively in setting styles than 'col' and 'colgroup' elements.see <col> and <table>
<table id="coltable2">
<caption>My Table 'col' Example</caption>
<colgroup>
<col span="2" style="background-color: lightblue;" />
<col style="background-color: lightyellow;" />
</colgroup>
<thead>
<tr>
<th style="width:auto;">header 1</th>
<th style="width:auto;">header 2</th>
<th style="width:auto;">header 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>body 1</td>
<td>body 2</td>
<td>body 3</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>footer 1</td>
<td>footer 2</td>
<td>footer 3</td>
</tr>
</tfoot>
</table>
Below, you can see that this element is only used for grouping columns for styling purposes, when CSS can do this much better without this element but using classes.
header 1 | header 2 | header 3 |
---|---|---|
body 1 | body 2 | body 3 |
footer 1 | footer 2 | footer 3 |
<colgroup span="4" />
). But this column grouping is inferred by the table headers and cells, so is redundant and rarely used.
<bq>
<p>Quoted text goes here</p>
<credit>Credit source text goes here</credit>
</bq>
Quoted text goes here
<h4>Products List</h4>
<ol>
<li>This is <data value="7345">Product #1</data></li>
<li>This is <data value="1847">Product #2</data></li>
<li>This is <data value="3890">Product #3</data></li>
</ol>
<form id="datalistform1" name="datalistform1" action="#" method="get">
<label for="datalistname1" title="My Datalist">Double-lick to Choose a Browser from The Datalist:</label>
<br />
<input type="text" id="datalistname1" name="datalistname1" value="" size="20" maxlength="20" title="Double-click to Choose" aria-label="Browser" tabindex="0" list="browserlist" placeholder="Double-click to choose..." />
<datalist id="browserlist" title="Browser List" aria-label="Browser List" role="listbox">
<option value="Internet Explorer"></option>
<option value="Firefox"></option>
<option value="Chrome"></option>
<option value="Opera"></option>
<option value="Safari"></option>
</datalist>
<button id="datalistbutton1" name="datalistbutton1" type="submit" value="submit" form="datalistform1" title="Submit" tabindex="0" aria-label="Submit">Submit</button>
</form>
see <dl>
see also <in>
<p>Did you know my favorite color is <del>green</del> <ins>aqua</ins>.</p>
Did you know my favorite color is green aqua?
<ins>
) will often follow the deleted one (<del>
) to indicate a replacement of new text for the deleted one and to emphasize the change.also see <summary>
The "details" example is show below. It includes a 'summary' element with a click-able title which reveals additional 'details' element text below.
<details id="detailsexample1">
<summary style="background-color: #ccccccff;box-shadow: 2px 2px 3px #aaa;">© Copyright 2022</summary>
<div style="margin:0;padding:.2em 1em;background-color: #efefef;box-shadow: 2px 2px 3px #aaa;">
<p>Owned by Company ABC. All Rights Reserved.</p>
<p>All content and graphics on this web site are the property of Company ABC.</p>
</div>
</details>
Owned by Company ABC. All Rights Reserved.
All content and graphics on this web site are the property of Company ABC.
<summary>
element or title, followed by multiple HTML content elements which will be hidden until the summary text is clicked. The supporting browser controls the hiding and click-able arrow interactive elements. Because the 'details' element is a "list", setting its CSS display to anything other than "display: list-item" will remove the dropdown toggle arrow. You can add your own custom toggle arrow but that is beyond the scope here as browser support would be very sketchy.
<p>Learn more about the <a href="#sun">Sun</a></p>
<p>The <dfn id="sun" title="Our Shining Celestial Body">Sun</dfn> is the name of the local star in our solar system.</p>
Learn more about the Sun
The Sun is the name of the local star in our solar system.
<p><dfn><abbr title="HyperText Markup Language - Version 5">HTML5</abbr></dfn> is the fifth version of the standard markup language used in creating web pages.</p>
HTML5 is the fifth version of the standard markup language used in creating web pages.
<dt><dfn>HTML</dfn></dt>
. See 'dl'.(Paste the HTML and JavaScript block below into your web page to recreate my new and improved "cross-browser" HTML5 dialog box)
<div id="dialogbox_alt" role="dialog" aria-label="Alternate Dialog">
<dialog id="dialogbox" aria-label="Dialog" style="
display:none;
width: 20em;
min-height: 15em;
max-width: 50%;
padding: 1em;
background-color: #fff;
border: 2px solid #999;
border-radius: .5em;
/* center all dialogs */
position: fixed;
top: 50%;
left: 50%;
margin-left: -10em;
margin-top: -5em;
z-index: 99;
/* create background screen */
box-shadow: 0 0 0 9999px rgba(0,0,0,0.6);
">
<form id="formdialog1" action="#" method="get" style="position:relative;
width:100%;
height:100%;
padding:0;
margin:0;">
<span id="dialogcloser" style="display:inline-block;
cursor:pointer;
padding:.2em;
position:absolute;
top:-5px;
right:-5px;">X</span>
<div style="padding:1em;">
<p>
<label for="animals1" title="Animals"> * Choose an Animal:</label>
<select id="animals1" name="animals1" size="1" required="required" aria-required="true" aria-label="List of Animals" tabindex="0">
<option value="" selected="selected">- choose an animal -</option>
<option value="elephant">Elephant</option>
<option value="zebra">Zebra</option>
<option value="lion">Lion</option>
</select>
</p>
<p>
<button type="submit" name="dialogconfirm" value="confirm">Confirm</button>
</p>
</div>
</form>
</dialog>
</div>
<button id="dialogopener" type="button">Open A Dialog Box</button>
Features of My Custom Dialog Box:
* Internet Explorer Browser Support:
<dir>
<li>Directory Item #1</li>
<li>Directory Item #2</li>
</dir>
<div style="padding: 1em;border:1px solid black;">
<p>This text is inside a "div" container</p>
</div>
This text is inside a "div" container
<dl>
<dt id="dog1">Dog</dt>
<dt>Puppy</dt>
<dt>Mutt</dt>
<dd aria-labelledby="dog1">Man's best friend</dd>
<dt id="cat1">Cat</dt>
<dt>Kitty</dt>
<dd aria-labelledby="cat1">Our feline friends</dd>
</dl>
<dl>
<dt id="html1"><dfn><abbr title="Hypertext Markup Language">HTML</abbr></dfn></dt>
<dd aria-labelledby="html1">The standard markup language for creating web pages.</dd>
</dl>
<dt><dfn>HTML</dfn></dt>
. When you wrap a 'dfn' tag around a term, you are officially "defining" a term and your list is now acting like a true dictionary or lexicon. See 'dfn'.<dt><abbr title="Hypertext Markup Language">HTML</abbr></dt>
. See 'abbr'.see <dl>
see <html>
<html>
element for a full description.
<p>This text has <em>emphasis</em>.</p>
This text has emphasis.
<embed id="embed1" alt="embed: Electronic Sheep Video" style="width:324px;height:240px;border:1px solid #000;" src="video1.mp4" type="video/mp4" loop="false" title="Electronic Sheep Video" aria-label="Embedded File: Electronic Sheep Video">
<noembed>Your browser does not support this media object or the embed element.</noembed>
</embed>
(Above is an example using the embed tag. Depending on your browser and the plug-in supported, you should see an "MP4" (MPEG4) video file. If you do not it is because this video format or codec is not supported by your browser.)
see <legend>
<form id="fieldsetform" name="fieldsetform" action="#" aria-label="Login" title="Login">
<fieldset id="fieldset1" name="fieldset1" form="fieldsetform">
<legend style="background-color: #ccc;color: #fff;">Login</legend>
<p>
<label for="fieldsetinput1" title="Username">Username:</label>
<input type="text" aria-label="Username" id="fieldsetinput1" name="fieldsetinput1" size="20" maxlength="10" value="" title="Username" tabindex="0" autocomplete="username" />
</p>
<p>
<label for="fieldsetinput2" title="Password">Password:</label>
<input type="password" aria-label="Password" id="fieldsetinput2" name="fieldsetinput2" size="20" maxlength="10" value="" title="Password" tabindex="0" autocomplete="new-password" />
</p>
<p><button id="fieldsetsubmit1" aria-label="Submit" aria-pressed="false" title="Login" tabindex="-1" disabled="disabled" aria-disabled="true">Login</button></p>
</fieldset>
</form>
Old Browsers Only - Fieldset Design
fieldset {
display: block;
width: auto;
height: auto;
padding: 8px 16px 16px 16px;
margin: 8px 0px;
background-color: transparent;
/*/*//*/background-color: white;/*end*/
border: 2px solid #bbbbbb;
}
Modern Browsers Only - Fieldset Design
fieldset {
display: block;
width: auto;
height: auto;
max-width: 100%;
padding: .5em 1em 1em 1em;
padding: .5rem 1rem 1rem 1rem;
margin: .5em 0em;
margin: .5rem 0rem;
border-radius: .2em;
border-radius: .2rem;
background-color: #f3f3f3;
border: 2px solid #bbb;
}
The <fig> element is a lost relic from old HTML 3.0 (1995). It is no longer supported, but oddly was redesigned back into HTML5's 'figure' element.
<fig src="cat.jpeg" align="left">
<caption>My cat's name is 7-Up!</caption>
<p>My cat loves fish and to roam outside after his meal.</p>
<credit>Cat Daddy wrote this!</credit>
</<fig>
see <figure>
<figure style="padding: .5rem;border:1px solid #bbb;background: #f0f0f0;width: auto;height: auto;display: inline-block;" aria-labelledby="myfigureimage">
<img id="figureimage" src="www.jpg" width="255" height="200" alt="image:World Wide Web" title="World Wide Web Image" onerror="this.onerror=null;" loading="lazy" />
<figcaption id="myfigureimage" style="text-align:center;display:block;">This is the <cite>World Wide Web!</cite></figcaption>
</figure>
* I have created a very simple 'figure' example below using a plain image. But, you can wrap figures around many types of objects to create more complex captions (see my examples in "Best Practices" below).
<font size="3" face="courier" color="#0000ff">This text is wrapped by 'font' tags and should be blue "courier" font if your browsers supports older HTML4 'font' attributes.</font>
See also <header>, <nav>, <main>, <section>, <article>, and <aside>
<footer id="footer" role="contentinfo" aria-label="Footer" >Footer</footer>
* A typical web page structure is shown above.
Shown below, is a complete code sample for the <form> element which you can copy-and-paste into your web projects. It has a complete set of attributes (I recommend), plus an example of every HTML form field element possible in a traditional form. Use it as a template for all your web projects, modifying it as needed. The visual design for this form is shown below the code.
<form id="f1" name="f1" method="post" action="#" title="Form Example" aria-label="Form Example" autocomplete="off" autocapitalize="off" spellcheck="false">
<fieldset id="f1_fieldset" name="f1_fieldset" form="f1">
<legend style="background-color:#999;color: #fff;">Form Example</legend>
<fieldset id="f1_fieldset_1" name="f1_fieldset_1" form="f1">
<legend style="background-color: #aaa;color: #fff;">Text Example</legend>
<p>You can add plain text inside a form.</p>
</fieldset>
<fieldset id="f1_fieldset_2" name="f1_fieldset_2" form="f1">
<legend style="background-color: #aaa;color: #fff;">Login with Submit</legend>
<div>
<input type="text" id="f1_username" name="f1_username" size="20" value="" autocomplete="username" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="0" placeholder="Enter username here..." title="Enter Username" aria-label="Username" required="required" aria-required="true" /> *
</div>
<div>
<input type="password" id="f1_password" name="f1_password" size="20" minlength="8" maxlength="12" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,12}" value="" autocomplete="new-password" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="0" placeholder="Enter password here..." title="Enter Password: (8-12) characters, must contain one number, one uppercase and lowercase letter" aria-label="Password" required="required" aria-required="true" /> *
</div>
<div>
<button id="f1_login" name="f1_login" value="Login Submit" title="Login" aria-label="Login" aria-pressed="false" tabindex="0" form="f1">Login</button>
</div>
</fieldset>
<fieldset id="f1_fieldset_3" name="f1_fieldset_3" form="f1">
<legend style="background-color: #aaa;color: #fff;">Checkboxes</legend>
<p>Which colors do you like?</p>
<div>
<input type="checkbox" id="f1_checkboxgreen" name="f1_checkboxgroup" "autocomplete=off" value="green" title="green" aria-label="green" aria-checked="false" tabindex="0" />
<label for="f1_checkboxgreen" title="Green" style="color:green;">Green</label>
</div>
<div>
<input type="checkbox" id="f1_checkboxred" name="f1_checkboxgroup" "autocomplete=off" value="red" title="red" aria-label="red" aria-checked="true" tabindex="0" checked="checked" />
<label for="f1_checkboxred" title="Red" style="color:red;">Red</label>
</div>
<div>
<input type="checkbox" id="f1_checkboxblue" name="f1_checkboxgroup" "autocomplete=off" value="blue" title="blue" aria-label="blue" aria-checked="false" tabindex="0" />
<label for="f1_checkboxblue" title="Blue" style="color:blue;">Blue</label>
</div>
</fieldset>
<fieldset id="f1_fieldset_4" name="f1_fieldset_4" form="f1">
<legend style="background-color: #aaa;color: #fff;">Radio Buttons</legend>
<p>Choose A Favorite Pet</p>
<div>
<input type="radio" id="f1_dog" name="f1_radiogroup" "autocomplete=off" value="dog" title="dog" aria-label="dog" aria-checked="false" tabindex="0" />
<label for="f1_dog" title="Dog">Dog</label>
</div>
<div>
<input type="radio" id="f1_cat" name="f1_radiogroup" "autocomplete=off" value="cat" title="cat" aria-label="cat" checked="checked" aria-checked="true" tabindex="0" />
<label for="f1_cat" title="Cat">Cat</label>
</div>
<div>
<input type="radio" id="f1_bird" name="f1_radiogroup" "autocomplete=off" value="bird" title="bird" aria-label="bird" aria-checked="false" tabindex="0" />
<label for="f1_bird" title="Bird">Bird</label>
</div>
</fieldset>
<fieldset id="f1_fieldset_5" name="f1_fieldset_5" form="f1">
<legend style="background-color: #aaa;color: #fff;">Textarea</legend>
<div>
<textarea id="f1_textarea" name="f1_textarea" title="Textarea" aria-label="Textarea" tabindex="0" contenteditable="true" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="true" maxlength="200">Enter your text here...</textarea>
</div>
</fieldset>
<fieldset id="f1_fieldset_6" name="f1_fieldset_6" form="f1">
<legend style="background-color: #aaa;color: #fff;">File Upload</legend>
<div>
<input type="file" id="f1_fileupload" name="f1_fileupload" title="Multiple File Upload" aria-label="Multiple File Upload" tabindex="0" enctype="multipart/form-data" accept="image/*" multiple="multiple" aria-multiselectable="true" />
</div>
</fieldset>
<fieldset id="f1_fieldset_7" name="f1_fieldset_7" form="f1">
<legend style="background-color: #aaa;color: #fff;">Select List</legend>
<div>
<select id="f1_select" name="f1_select" title="Select List" aria-label="Select List" multiple="multiple" size="6" aria-multiselectable="true" tabindex="0">
<option value="" selected="selected">-- select an option --</option>
<option value="1">one</option>
<option value="2">two</option>
<option value="3">three</option>
<option value="4">four</option>
<option value="5">five</option>
<option value="6">six</option>
<option value="7">seven</option>
<option value="8">eight</option>
<option value="9">nine</option>
<optgroup label="ten to twenty" role="group">
<option value="10">ten</option>
<option value="20">eleven</option>
</optgroup>
</select>
</div>
</fieldset>
<fieldset id="f1_fieldset_8" name="f1_fieldset_8" form="f1" >
<legend style="background-color: #aaa;color: #fff;">Hidden Inputs</legend>
<div>
<input type="hidden" id="f1_hidden1" name="f1_hidden1" value="one" aria-hidden="true" tabindex="-1" />
<input type="hidden" id="f1_hidden2" name="f1_hidden2" value="two" aria-hidden="true" tabindex="-1" />
</div>
</fieldset>
<fieldset id="f1_fieldset_9" name="f1_fieldset_9" form="f1" >
<legend style="background-color: #aaa;color: #fff;">Image Button</legend>
<div>
<input type="image" src="yourimagebutton.gif" id="f1_imagebutton" name="f1_imagebutton" alt="Image Button" title="Image Button" aria-label="Image Button" tabindex="0" form="f1" style="border:2px solid #bbb;" />
</div>
</fieldset>
<fieldset id="f1_fieldset_10" name="f1_fieldset_10" form="f1" >
<legend style="background-color: #aaa;color: #fff;">Reset, Disabled, and Read-only</legend>
<div>
<input type="reset" id="f1_resetinput" name="f1_resetinput" value="Reset Button" title="Reset Button" aria-label="Reset Button" tabindex="0" form="f1" />
</div>
<div>
<input type="submit" id="f1_disabledinput" name="f1_disabledinput" value="Disabled Button" title="Disabled Button" aria-label="Disabled Button" disabled="disabled" aria-disabled="true" tabindex="-1" form="f1" />
</div>
<div>
<input type="text" id="f1_readonlyinput" name="f1_readonlyinput" size="20" maxlength="20" value="This is Read-only Text" readonly="readonly" autocomplete="off" tabindex="-1" title="Read-only Text" aria-label="Read-only Text" />
</div>
</fieldset>
<fieldset id="f1_fieldset_11" name="f1_fieldset_11" form="f1" >
<legend style="background-color:#aaa;color:#fff;">Plain Buttons</legend>
<div>
<input type="button" id="f1_plaininputbutton" name="f1_plaininputbutton" value="Plain 'Input' Button" title="Plain 'Input' Button" aria-label="Plain 'Input' Button" tabindex="0" form="f1" />
</div>
<div>
<button type="button" id="f1_plainbutton" name="f1_plainbutton" value="Plain 'Button' Button" title="Plain 'Button' Button" aria-label="Plain 'Button' Button" tabindex="0" form="f1">Plain 'Button' Button</button>
</div>
</fieldset>
<fieldset id="f1_fieldset_12" name="f1_fieldset_12" form="f1" >
<legend style="background-color: #aaa;color: #fff;">Submit Buttons</legend>
<div>
<input type="submit" id="f1_inputsubmit" name="f1_inputsubmit" value="Input Submit" title="Input Submit" aria-label="Input Submit" tabindex="0" form="f1" />
</div>
<div>
<button type="submit" id="f1_buttonsubmit" name="f1_buttonsubmit" value="Button Submit" title="Button Submit" aria-label="Button Submit" tabindex="0" form="f1">Button Submit</button>
</div>
</fieldset>
</fieldset>
</form>
see <frameset> and <noframes>
<frameset cols="50%,50%">
  <frame src="https://www.w3.org/TR/html4/present/frames.html#h-16.2.1"></frame>
  <frame src="https://www.w3.org/TR/html4/present/frames.html#h-16.2.2"></frame>
  <noframes>
  <p>Alert! Frames are not supported in your web browser. This frame should includes two page views of the W3C website.</p>
  </noframes>
</frameset>
* If you do not see anything below, then the 'frameset, 'frame', and 'noframes' elements are not supported in your browser.
see <frame> and <noframes>
<frameset cols="50%,50%">
 <frame src="https://www.w3.org/TR/html4/present/frames.html#h-16.2.1"></frame>
  <frame src="https://www.w3.org/TR/html4/present/frames.html#h-16.2.2"></frame>
  <noframes>
  <p>Alert! Framesets are not supported in your web browser. This frameset should includes two page views of the W3C website.</p>
  </noframes>
</frameset>
* If you do not see anything below, then the 'frameset, 'frame', and 'noframes' elements are not supported in your browser.
see <html>
<html>
element for a full description.See also <nav>, <main>, <footer>, <section>, <article>, and <aside>
<header id="header" role="banner" aria-label="Header" >Header</header>
* A typical web page structure is shown above.
An example of a typical "heading" page layout is shown below. This HTML would appear inside the <main> element in the 'body' of your web page:
<section aria-labelledby="heading1">
<h1 id="heading1" title="Example of an H1 Heading">H1 Heading</h1>
<div>
<h2>H2 Heading</h2>
<p>text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 </p>
<h2>H2 Heading</h2>
<p>Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 </p>
</div>
</section>
text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1 text 1
Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2 Text 2
<hgroup>
<h1>Chapter 1</h1>
<h2>Intro to HTML Fundamentals</h2>
</hgroup>
<p>Page text starts here...</p>
Page text starts here...
<p>text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p>
<hr />
<p>text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p>
text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
<source>
). They then apply this argument to a whole host of HTML elements, like 'img', 'hr', and others. I disagree! The horizontal rule is no different! They argue the <hr>
format is the right format now in HTML5, and should not indicate it has ended. But they are WRONG! You should ALWAYS design your HTML5 to avoid this "void" design and add a forward slash at the end of your horizontal rule element like so: <hr />
. This is completely acceptable in HTML5, as HTML5 is now a living standard that accepts all types of formats and changes, unlike the W3C recommendations which were more enforced. Using my HTML rule allows your pages to match XHTML/XML standards, allows your HTML to be read faster and cleaner by 3rd party parsers, improves the DOM manipulated by JavaScript, and best of all actually "ends" the horizontal element correctly! The "void" version does not, and spreads inconsistency throughout your websites. As you write thousands of web pages over time, making sure all your HTML is XML-friendly with ending "/" characters means your HTML is now robust, consistent, cross-compatible with multiple standards, fully XML-compatible, and best of all CORRECT!I have decided to cover all the major HTML "framework" elements in one section so you can see how they create the modern HTML5 page when combined. They include the following: <!doctype>
, <html>
, <head>
, <title>
, <meta>
, <body>
, plus the "doctype" definition tag <!doctype html>
that goes at the top of the page. Combined, these elements are required in all legacy and modern web applications, and define your current web page as HTML5.
I have created a "bare bones", basic HTML template below with recommended values and meta tags I recommend you use in all your HTML pages. You can cut-and-paste it into any blank page and use it as a solid HTML5 starting web page template. Just change the values in the attributes for your specific requirements. All other elements listed in this tutorial would appear inside either the <head>
or the <body>
elements shown below. Note: The 'meta' elements used can include many more than is shown here, or far less, if you choose. Most HTML5 parsers in browsers will assume values for most of these meta tags, anyway, so most are optional. See my list of required meta tags in the section below.
If you want a full featured HTML5 template with all the other HTML "goodies" included, like "external" CSS style sheets or JavaScript links used in this section, visit my section below called, "My Complete HTML5 Template".
<!doctype html>
<html xml:lang="en-us" lang="en-us">
<head>
<title>Your Website Title</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"
<meta http-equiv="content-style-type" content="text/css; charset=utf-8;">
<meta http-equiv="content-script-type" content="text/javascript">
<meta name="viewport" content="width=device-width,initial-scale=1.0,shrink-to-fit=no">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="keywords" content="keyword1, keyword2, keyword3">
<meta name="author" content="Your Name, https://yourwebsite.com/">
<meta name="description" content="Your Web Page Description, author Your Name 2022">
<meta name="copyright" content="© Copyright 2022, Your Name | All Rights Reserved">
<meta name="classification" content="business">
<meta name="rating" content="general">
<meta name="revision" content="1.0">
<meta name="distribution" content="global">
<meta name="resource-type" content="document">
<meta name="doc-class" content="Living Document">
<meta name="document-type" content="Public">
<meta name="document-rating" content="General">
<meta name="robots" content="all">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body text="black" bgcolor="white">
...
</body>
</html>
<!doctype html>
- This truncated, "incomplete" DOCTYPE version for HTML is now required in all HTML5 pages and defines your document as a "true" HTML5 document. As a result, you MUST use this code at the top of every web page if you want browsers to define your pages as HTML5. The newer web browsers will generally assume you are always using HTML5 by default. But, older browser will not. Most older browsers will default to an older form of "tag soup" HTML, or "quirksmode" HTML, when they see this unusual doctype at the head of your web page. What is defined at the top of the web page often controls the type of HTML used by the older browsers, like IE6. This was known as "doctype switching" in the old days. Keep in mind that most browsers created after 2010 also still support some form of doctype switching, but will generally know HTML5, which is likely 90-99% of most browsers viewing your website in 2022. Many browsers created before 2010 knew XHTML, however, which relied on doctypes as well to define their XHTML applications as a form of XML. That means many browsers created after, say 2001, may try and use their "switching" abilities to use the HTML5 DOCTYPE and interpret your web page as a form of invalid XHTML. That is generally ok, as we are not worried about validation in HTML5. Remember, its a "sloppy" standard and very forgiving in many older browsers, allowing many forms of HTML to be used that likely are still valid in XHTML and HTML4 browsers. There is an "XHTML5 Polyglot" DOCTYPE you can use instead, if you are truly interested in supporting XHTML in these older agents. I do not cover that here as its a subtype of the same HTML. Because many older XHTML-friendly web browsers use DOCTYPES in general to define whether a page is XHTML/XML friendly or plain HTML, this "partial" HTML5 DOCTYPE format might trigger some older agents to parse the page as XHTML rather than "tag soup" HTML. Because most web servers, however, rarely delivered true XHTML pages as XML, in the strict sense, these pages would likely fall back to HTML. The HTML tags supported between HTML4 and XHTML1.1 are close to the same, anyway. (My "best practices" section in this page covers a way to make sure your HTML5 works in XHTML5 by using XML-friendly code, btw.) So my point is, do not worry about these issues in older browsers and the HTML5 DOCTYPE. By following my recommendations in this tutorial, your code will work GREAT if one of these older XHTML browsers were to try and parse your page as XHTML/XML using this doctype. Because most would not accept an "incomplete" DOCTYPE as HTML5 uses, its likely they would fall back to a form of HTML4.1, in most cases. But, just realize DOCTYPES for decades have factored into how older browsers interpret what flavor of HTML you are using. But, know that the majority of the time, because none of the older browsers will know what HTML5 is, they will just consider your web page "tag soup" HTML, using the server's default HTTP content-type of "text/html" to define the page as generic HTML.<html xml:lang="en-us" lang="en-us">
- 'html' is the root element of every website, HTML5 included! As such it defines your page to user agents and browsers as HTML. This includes all the older versions, like HTML3.2 and HTML4.1. Using the HTML5 DOCTYPE mentioned above in combination with this root element, your pages are recognized as HTML5 by the nearly all user agents online today. In the past, there have been several attributes added to 'html' tags to help browsers define the language the page is using. "lang" was the main one. Because different browsers come with so many encoding types, Unicode layers, legacy encoding sets, and numbering schemes for characters, its important you always assign a language used (lang="en-us" for US English). This then helps browsers and search engines interpret or "decode" your web page and its character sets better. It also helps them determine if they do not support a given language used in your web page. Because HTML5 uses UTF-8 by default, it will support all of Unicode and a million or more text encodings and hundreds of language sets, emoticons, etc. used around the world. These browsers also are good at "sniffing" the language used. You can leave off the language attribute for that reason, but I do not recommend it, especially if your page is in a non-English speaking language. The reason is the characters used might not be supported in countries or browsers for some users. There may be mis-interpretations between closely aligned languages, as well. In XHTML, an "xml" version of the "lang" attribute was added and is also optional. I added it here so your pages are XHTML-friendly.<head>
- The 'head' element holds all the meta data for your page and any preprocessing of external files, styles, or scripts required by the page. These include all non-visual design elements in the web page.<title>
- The 'title' element appears directly under the parent 'head' element and should come first before all other elements. It is used by browsers to display the title of your web page in tabs, bookmarks, shortcuts, etc. in the browser. You may see your title appear in the browsers tab text, for example. It also is used by search engines in both their search application titles in search listings and also for determining keywords used in the page when they build page rank. If your website's title has text and keywords that also appear prominently in the subject matter of the web page (i.e. headings and text), then the 'title' element can assist in providing better search engine rankings for your page.<meta>
- "Meta tags" have been around since the 1990's and have changed over the years in type, variety, volume, function, and affect in websites. Because of these changes, the meta tags I have listed in the code above are all optional. None of them are required for your website to function. Only a few are highly recommended, though not critical. If you avoid using the handful that are required, you might see small, very minor effects in how your website is displayed or function in some devices, search engines, or browsers. But none are critical, in my opinion. I have listed the important ones I recommend you use, below:
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta charset="utf-8">
. I disagree, as the first version above supports a wide range of old and new browsers. As mentioned, when you use the HTML5 DOCTYPE mentioned above, the browser will assume your HTML5 page uses UTF-8 Unicode encoding. But older browsers will not. So, adding this value here helps them more than newer browsers. Encoding is how a document is saved in terms of the numbers representing characters and the byte sequence used to store them in memory or in the saved document. Over time, we have moved from ASCII in 8-bit to Unicode which holds ASCII and over a million additional characters. But most software today does not default to saving in Unicode, so much of what is saved in HTML pages is still using older encoding. The good news is ASCII, or all the English numbers and characters, translates perfectly into HTML5's UTF-8 unicode standard without any special requirements. It's when you start using foreign languages or special characters in web pages that you might see problems and might want to check how you encode your web pages. Because older browsers do not know HTML5 and its UTF-8 default encoding platform, they will not know to use Unicode when translating your web page. That is why you need this special required meta tag. When using this "charset" tag, do remember to place it right after the 'title' element at the very top of your 'head' element (in first 1024 or 256 bytes of page byte code), as the earlier browsers see the encoding type, the faster they parse your page. Web Servers send text in blocks, so that explains the memory limit values and why its critical you send this in the first bit of code from the server. UTF-8 is always the standard for HTML5 anyway, but this tag helps enforce that fact to all browsers and user agents that parse your web page. In most cases, as I describe in my "Best Practices" section below, browsers use a wide variety of techniques starting with HTTP headers from the server and BOM marks to "detect" what encoding HTML pages, CSS, and script files are encoded in. So, you should not worry too much about all that, as many inexperienced web developers try and convince you that you should.<meta name="viewport" content="width=device-width, initial-scale=1.0,shrink-to-fit= no" />
<meta name="keywords" content="keyword1, keyword2, keyword3" />
<meta name="description" content="Your Web Page Description, author Your Name 2022" />
<meta name="author" content="Your Name, https://yourwebsite.com/" />
<body text="black" bgcolor="white">
- The 'body' element contains all your visible HTML elements and page content seen by users online. Anything that needs to be viewed or processed goes in the 'body' element, including some scripting blocks at the end, though the 'head' element is a better place to manage scripting. Note that like all the other elements listed in this section, 'body' is required to create an HTML web page.
<ibobject name="backstage_object />
also see <frameset>
<figure aria-labelledby="iframecaption1" style="padding: .5rem;border: 1px solid #bbb;background: #f0f0f0;width: 400px;height: 300px;display: block;text-align: center;">
<iframe id="myiframename" name="myiframename" title="Internet Archive Movies" loading="lazy" referrerpolicy="no-referrer" style="width:auto;height:auto;min-width:100%;min-height:80%;" src="about:blank" srcdoc="<!doctype html><html xml:lang='en-us' lang='en-us'><head></head><body style='width: auto;height: auto;text-align: center;background: white;'><p>Welcome to My Iframe!</p></body></html>"></iframe>
<figcaption id="iframecaption1" style="font-size: smaller;"><a href="https://archive.org/details/TheSpiritOf43_56" target="myiframename" title="Donald Duck Movie" rel="noreferrer nofollow noopener">Load Donald Duck Movie</a><br /><a href="https://archive.org/details/CC_1914_08_31_TheGoodforNothing" target="myiframename" title="Charlie Chaplin Movie" rel="noreferrer nofollow noopener">Load Charlie Chaplin Movie</a><br /><a href="about:blank" target="myiframename" rel="noreferrer nofollow noopener">Load Blank Screen</a></figcaption>
</figure>
Notes on My Iframes Example: Notice I have wrapped the 'iframe' element with the new HTML5 'figure' element, like I do with 'video' elements. This allows you to use the caption as a tool to add alternate video URL links. I have also added styles that allows the iframe to expand as the figure expands. It is often difficult to control the iframe size. For that reason stick with styles and use the 'figure' element to control 'iframe' sizes. I am also demonstrating use of a "about:blank" starting page with custom HTML for the source. You can also link to a blank HTML page. The added links inside 'figcaption' are optional and show how you can allow users to load other files, pages, or objects into your iframes.
Remember, iframes are a security risk to many browsers, so you must limit its use unless you want to add the new "sandbox" or other security attributes, which I do not recommend at this time.
<ilayer>Text Content Here</ilayer>
also see <picture>
Below is the more traditional way to use images in web pages. If you just need an image to appear in a web page, you can drop in the 'img' element anywhere in your page. Note: The sample code below has a full suite of attributes I recommend you use which will allow your image to perform at its best in various scenarios in HTML.
<img id="imagexample1" style="border: 4px solid #999;" src="www.jpg" width="255" height="200" alt="image: World Wide Web" title="The World Wide Web" aria-label="Image of the World Wide Web" loading="lazy" onerror="this.onerror=null;" referrerpolicy="no-referrer" />
Most 'img' elements are "inline", meaning they flow with text horizontally across the page. Text does not wrap around the image by default but with the image horizontally. This allows you to drop images inside of paragraphs or text and they become part of the flow. Many people want text to flow around images, however, and float inside paragraphs. In most cases, text will not scroll around the image like this unless you change its display to "display:block" and add "float:left" in CSS. In the old days you could avoid this and set the "align:left" attribute on the 'img' element and force text to scroll to the right of it with mixed results. But it was not reliable as the image remained an "inline element" like the text beside it and part of the normal flow of text. I recommend you manipulate the image instead to float as described above using CSS rather than the "align" attributes on the 'img' tag.
<div style="padding: 1em;border: 1px solid #999;background-color: #ccc;">
<img id="imagexample2" style="width: 255px;height: 200px;display: block;float: left;margin: 0em 1em 1em 0em;border: 4px solid #999;" src="www.jpg" width="255" height="200" alt="image: World Wide Web" title="The World Wide Web" aria-label="Image of the World Wide Web" loading="lazy" onerror="this.onerror=null;" referrerpolicy="no-referrer" />
<h5>Sample Title</h5>
<p>text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p>
<p>text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p>
<div id="clearingdiv" style="clear: both;"><!--empty--></div>
</div>
text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text
Below is the more modern HTML5 way to use the 'img' element. Below I have wrapped the 'img' element in a 'figure' element, then a 'picture' element. The 'figure' element provides a 'figcaption' or text caption for the image, assisting non-visual readers. The 'picture' element provides alternative image formats based on browser support, viewport size, or other checks in the <source> tags. The browser first checks these 'source' elements one at a time, and if the image "type" is supported and/or viewport dimensions match, then the alternate "src" image is passed into the 'img' element below. If none are supported, then the default 'img' tag's image "src" is used. Understand that 'picture', like 'figure', is just a hollow "shell" element and does not do anything other than to group images with these other features, as well as give the 'img' tag alternate image choices. It simply injects alternative image formats into the 'img' element, if the user's browser supports them. So keep in mind, the 'img' element remains the PRIMARY container of the image inside all these other elements.
The 'img' element below also has a set CSS "style" attribute with variable width and height added to support the possible variable dimensions of the alternate image types assigned by the 'source' elements. It does have "width" and "height" attributes whose values are based on its default image, which the browser should only use if it defaults to its first image. But those will be ignored as each source image with different dimensions is applied.
So, if you see a "flowering tree" image ("webp" type) below, your browser supports one of the new alternate HTML5 image formats that the picture's 'source' element has assigned your 'img' element. If you see the "weather map" image it means your browser does not understand the WebP image type or failed the "media" viewport check in the previous 'source' element. Finally, if you see the default 'img' element's "World Wide Web" globe image ("jpg" type), the previous two image types failed and your browser only supports "jpegs".
<figure aria-labelledby="imgcaption3" style="padding: .5rem;border: 1px solid #bbb;background: #f0f0f0;width: auto;height: auto;display: inline-block;">
<picture id="imgpicture3">
<source srcset="image.webp" type="image/webp" />
<source srcset="weather.gif" media="(min-width: 800px)" type="image/gif" />
<img id="imagexample3" style="width: auto;height: auto;max-width: 100%;" src="www.jpg" width="255" height="200" alt="image: World Wide Web" title="The World Wide Web" aria-label="Image of the World Wide Web" loading="lazy" onerror="this.onerror=null;" referrerpolicy="no-referrer" />
</picture>
<figcaption id="imgcaption3" style="display:block;">
"Which Image Appears?"
</figcaption>
</figure>
* Note: My host provider does not support "WebP" images I found out, so if no "flowering tree" WebP image appears, it is not the code but my host provider. :(
<img id="srcset_image" src="medium.jpg" srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w" sizes="(max-width: 800px) 50vw" />
<a>
element recommendation above for two ways to fix this using "border:0" and adding "width" and "height"). Over time, use of image links like this have faded as far as use cases. But keep in mind, you can still do this trick. Just make sure you use enough CSS, tooltips, and figure captions on the image to design it properly and to tell users the purpose of the image link before they click on it.see <form> for more details using <input> in forms
Shown below is a complete code sample of the <input> element, which you can copy-and-paste into your web project. It has a complete set of inputs by "type", along with a rich set of attributes I recommend you use for each scenario. The visual design for this form is shown below the code. With these examples you have a complete set of inputs you can use in your web forms.
<form id="forminput" name="forminput" method="post" action="#" title="Input Example" aria-label="Input Example" autocomplete="off" autocapitalize="off" spellcheck="false">
<fieldset id="forminput_fieldset1" name="forminput_fieldset1" form="forminput">
<legend style="background-color:#aaa;color:#fff;">Input Types List</legend>
<div>
<input type="text" id="forminput_text" name="forminput_text" size="20" value="" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" placeholder="Enter text here..." title="Enter Text" aria-label="Text" tabindex="0" required="required" aria-required="true" />
<label for="forminput_text" title="Text">Text</label>
</div>
<hr />
<div>
<input type="password" id="forminput_password" name="forminput_password" size="20" minlength="8" maxlength="12" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,12}" value="" autocomplete="new-password" autocapitalize="off" autocorrect="off" spellcheck="false" placeholder="Enter password here..." title="Enter Password: (8-12) characters, must contain one number, one uppercase and lowercase letter" aria-label="Password" tabindex="0" required="required" aria-required="true" />
<label for="forminput_password" title="Password"> * Password</label>
</div>
<hr />
<div>
<input type="button" id="forminput_button" name="forminput_button" value="Button" title="Button" aria-label="Button" tabindex="0" aria-pressed="false" form="forminput" onClick="JavaScript:alert('::: This Button Type only works with Added JavaScript :::');return false;" />
<label for="forminput_button" title="Button">Button</label>
</div>
<hr />
<div>
<input type="submit" id="forminput_submit" name="forminput_submit" value="Submit" title="Submit" aria-label="Submit" tabindex="0" aria-pressed="false" form="forminput" />
<label for="forminput_inputsubmit" title="Submit">Submit</label>
</div>
<hr />
<div>
<input type="image" src="imagebutton1.gif" id="forminput_imagebutton" name="forminput_imagebutton" alt="Image Button" title="Image Button" aria-label="Image Button" tabindex="0" aria-pressed="false" form="forminput" style="border:2px solid #bbb;" loading="lazy" />
<label for="forminput_imagebutton" title="Image">Image</label>
</div>
<hr />
<div>
<input type="reset" id="forminput_reset" name="forminput_reset" value="Reset" title="Reset" aria-label="Reset" tabindex="0" aria-pressed="false" form="forminput" />
<label for="forminput_resetinput" title="Reset">Reset</label>
</div>
<hr />
<div>
<input type="file" id="forminput_fileupload" name="forminput_fileupload" tabindex="0" enctype="multipart/form-data" accept="image/*" multiple="multiple" aria-multiselectable="true" title="Multiple File Upload" aria-label="Multiple File Upload" />
<label for="forminput_fileupload" title="File">File</label>
</div>
<hr />
<p>Checkbox</p>
<div>
<input type="checkbox" id="forminput_checkboxgreen" name="forminput_checkboxgroup" "autocomplete=off" value="green" aria-checked="false" tabindex="0" title="green" aria-label="green" />
<label for="forminput_checkboxgreen" title="Green" style="color:green;">Green</label>
</div>
<div>
<input type="checkbox" id="forminput_checkboxred" name="forminput_checkboxgroup" "autocomplete=off" value="red" aria-checked="true" tabindex="0" checked="checked" title="red" aria-label="red" />
<label for="forminput_checkboxred" title="Red" style="color:red;">Red</label>
</div>
<div>
<input type="checkbox" id="forminput_checkboxblue" name="forminput_checkboxgroup" "autocomplete=off" value="blue" aria-checked="false" tabindex="0" title="blue" aria-label="blue" />
<label for="forminput_checkboxblue" title="Blue" style="color:blue;">Blue</label>
</div>
<hr />
<p>Radio</p>
<div>
<input type="radio" id="forminput_dog" name="forminput_radiogroup" "autocomplete=off" value="dog" aria-checked="false" tabindex="0" title="dog" aria-label="dog" />
<label for="forminput_dog" title="Dog">Dog</label>
</div>
<div>
<input type="radio" id="forminput_cat" name="forminput_radiogroup" "autocomplete=off" value="cat" checked="checked" aria-checked="true" tabindex="0" title="cat" aria-label="cat" />
<label for="forminput_cat" title="Cat">Cat</label>
</div>
<div>
<input type="radio" id="forminput_bird" name="forminput_radiogroup" "autocomplete=off" value="bird" aria-checked="false" tabindex="0" title="bird" aria-label="bird" />
<label for="forminput_bird" title="Bird">Bird</label>
</div>
<hr />
<p>Hidden</p>
<div>
<input type="hidden" id="forminput_hidden1" name="forminput_hidden1" value="one" aria-hidden="true" tabindex="-1" />
</div>
<hr />
<p><strong>Special Input Attributes</strong></p>
<div>
<input type="submit" id="forminput_disabledinput" name="forminput_disabledinput" value="Disabled Button" disabled="disabled" aria-disabled="true" tabindex="-1" form="forminput" title="Disabled Button" aria-label="Disabled Button" />
<label for="forminput_disabledinput" title="Disabled Button">Disabled Button</label>
</div>
<div>
<input type="text" id="forminput_readonly" name="forminput_readonly" size="20" maxlength="20" value="This is Read-only Text" readonly="readonly" autocomplete="off" tabindex="-1" title="Read-only Text" aria-label="Read-only Text" />
<label for="forminput_readonly" title="Read-Only Text">Read-only Text</label>
</div>
<div>
<input type="text" id="forminput_required" name="forminput_required" size="20" maxlength="20" value="This is Required Text" required="required" aria-required="true" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="0" title="Required Text" aria-label="Required Text" />
<label for="forminput_required" title="Required Text"> * Required Text</label>
</div>
<div>
<input type="text" id="forminput_states" name="forminput_states" size="2" minlength="2" maxlength="2" value="" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="0" title="Please Enter a US State Code (2)" aria-label="Pattern Attribute Text" pattern="[A-Za-z]{2}" />
<label for="forminput_states" title="States">Pattern Text</label>
</div>
<div>
<input type="text" id="forminput_hidden" name="forminput_hidden" size="20" maxlength="20" value="This is Hidden Text" hidden="hidden" autocomplete="off" tabindex="-1" title="Hidden Text" aria-label="Hidden Text" />
</div>
<hr />
<p><strong>Non-Recommended Elements that Use 'input'</strong></p>
<div>
<input type="text" id="forminput_datalist" name="forminput_datalist" value="" size="20" maxlength="20" tabindex="0" list="forminput_list" placeholder="Double-click to choose..." title="Double-click to Choose" aria-label="Fruit" />
<datalist id="forminput_list" title="Fruit List" aria-label="Fruit List" role="listbox">
<option value="apple"></option>
<option value="orange"></option>
<option value="pear"></option>
<option value="grape"></option>
<option value="banana"></option>
</datalist>
</div>
<div>
<input type="range" id="forminput_range" name="forminput_range" value="50" min="1" max="100" minlength="1" maxlength="3" tabindex="0" autocomplete="off" title="Slide the Range Indicator" aria-label="Slide the Range Indicator" /> +
</div>
<div>
<input type="number" id="forminput_number1" name="forminput_number1" value="0" min="1" max="100" minlength="1" maxlength="3" tabindex="0" title="Number" aria-label="Number" /> =
</div>
<div>
<output id="forminput_output1" name="forminput_output1" for="forminput_range forminput_number1" tabindex="0" value="0" title="Number Output" aria-label="Number Output"></output>
</div>
<hr />
</fieldset>
</form>
<form id="forminput2" name="forminput2" method="post" action="#" autocomplete="off" autocapitalize="off" spellcheck="false" title="New HTML5 Input Types" aria-label="New HTML5 Input Types">
<fieldset id="forminput2_fieldset" name="forminput2_fieldset" form="forminput2">
<legend style="background-color:#aaa;color:#fff;">*New HTML5 Input Types</legend>
<p><strong>Recommended New Types</strong></p>
<div>
<input type="search" id="forminput2_search" name="forminput2_search" value="" tabindex="0" autocomplete="on" aria-autocomplete="inline" required="required" aria-required="true" novalidate="novalidate" spellcheck="false" placeholder="Search this site..." title="Search" aria-label="Search" />
<label for="forminput2_search" title="Search"> * Search</label>
</div>
<div>
<input type="email" id="forminput2_email" name="forminput2_email" value="" tabindex="0" autocomplete="on" aria-autocomplete="inline" required="required" aria-required="true" placeholder="Enter an email address..." title="Enter a valid Email Address: x@x.com" aria-label="Email" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$" multiple="multiple" aria-multiselectable="true" />
<label for="forminput2_email" title="Email"> * Email</label>
</div>
<div>
<input type="tel" id="forminput2_tel" name="forminput2_tel" value="" tabindex="0" autocomplete="on" aria-autocomplete="inline" required="required" aria-required="true" placeholder="XXX-XXX-XXXX" title="Enter a valid US Phone Number: xxx-xxx-xxxx" aria-label="Phone" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" />
<label for="forminput2_tel" title="Telephone Number"> * Telephone</label>
</div>
<div>
<input type="number" id="forminput2_number" name="forminput2_number" value="0" min="1" max="100" minlength="1" maxlength="3" tabindex="0" autocomplete="off" required="required" aria-required="true" title="Enter a valid Number: 1-99" aria-label="Number" />
<label for="forminput2_number" title="Number"> * Number</label>
</div>
<div>
<input type="submit" id="forminput2_inputsubmit1" name="forminput2_inputsubmit1" value="Test" tabindex="0" form="forminput2" title="Press Submit to Test HTML5 Validation" aria-label="Press Submit to Test HTML5 Validation" />
</div>
<p><strong>Non-Recommended New Types</strong></p>
<div>
<input type="url" id="forminput2_url" name="forminput2_url" value="" tabindex="0" autocomplete="on" aria-autocomplete="inline" required="required" aria-required="true" spellcheck="false" placeholder="Enter a URL..." pattern="https?://.+" title="Enter a valid URL: http://..." aria-label="URL" />
<label for="forminput2_url" title="URL"> * URL</label>
</div>
<div>
<input type="date" id="forminput2_date" name="forminput2_date" value="" tabindex="0" autocomplete="off" required="required" aria-required="true" spellcheck="false" title="Date" aria-label="Date" min="2020-01-01" />
<label for="forminput2_date" title="Date"> * Date</label>
</div>
<div>
<input type="datetime-local" id="forminput2_datetimelocal" name="forminput2_datetimelocal" value="" tabindex="0" autocomplete="off" required="required" aria-required="true" spellcheck="false" title="Datetime-Local" aria-label="Datetime-Local" />
<label for="forminput2_datetimelocal" title="DateTimeLocal"> * Datetime-Local</label>
</div>
<div>
<input type="time" id="forminput2_time" name="forminput2_time" value="" tabindex="0" autocomplete="off" required="required" aria-required="true" spellcheck="false" title="Time" aria-label="Time" />
<label for="forminput2_time" title="Time"> * Time</label>
</div>
<div>
<input type="week" id="forminput2_week" name="forminput2_week" value="" tabindex="0" autocomplete="off" required="required" aria-required="true" spellcheck="false" title="Week" aria-label="Week" />
<label for="forminput2_week" title="Week"> * Week</label>
</div>
<div>
<input type="month" id="forminput2_month" name="forminput2_month" value="" tabindex="0" autocomplete="off" required="required" aria-required="true" spellcheck="false" title="Month" aria-label="Month" />
<label for="forminput2_month" title="Month"> * Month</label>
</div>
<div>
<input type="color" id="forminput2_color" name="forminput2_color" value="#ffffff" tabindex="0" autocomplete="off" required="required" aria-required="true" title="Color" aria-label="Color" />
<label for="forminput2_color" title="Color"> * Color</label>
</div>
<div>
<input type="range" id="forminput2_range" name="forminput2_range" value="50" min="1" max="100" minlength="1" maxlength="3" tabindex="0" autocomplete="off" required="required" aria-required="true" title="Slide the Range Indicator" aria-label="Slide the Range Indicator" />
<label for="forminput2_range" title="Range"> * Range</label>
</div>
<div>
<input type="submit" id="forminput2_inputsubmit2" name="forminput2_inputsubmit2" value="Test" tabindex="0" form="forminput2" title="Press Submit to Test HTML5 Validation" aria-label="Press Submit to Test HTML5 Validation" />
</div>
</fieldset>
</form>
* A typical web form is shown above.
<form>
for more details on "multipart/form-data"). The "file" input type also has a special attribute calls "accept", which allows you to control what types of files are uploaded by a user. In the code example above you can see how I have added "accept=image/*". This says to only allow images, but of any subtype or extension. The wildcard "*" attribute creates this "any" feature. There are many other arrangements of file types you can add to the "accept" attribute. I have listed a few below:
New HTML5 'input' element "types"
<form>
: Element Around Your 'input' Elements: When you wrap a form tag around a submit button 'input' control, it tells the browser your submit button is associated with a specific form "id" value and will only submit the field elements associated with that control. If you have multiple forms of forms and form fields to submit in a web page, it is crucial you know what input button submits which forms. You can still place the 'input' submit button element outside a form, if you give it a 'form' attribute with value associated with a specific form "id". In that case, it will still submit all input fields inside that specific form when pressed. However, I do not recommend you move any form controls or buttons outside of a parent form, as some older browsers may fail to submit the right data when submitted.<label>
Element with Your 'input' Element: Try and use the 'label' element before or after your 'input' tag, then add the "for" attribute with a value that matches the input's 'id' value to associate the two together. This links the label to the 'input' or form field and allows the browser, search engines, and screen readers to connect the two, adding semantic meaning. Always add a 'title' attribute to labels with a description of the field in order to associate the label with it. This is just good usability. Often, the browsers will float the label text beside the form control, with minimal CSS design changes needed to position it (see my code samples above for examples of labels and inputs). Additionally, in most browsers "clicking" on the label's text auto-selects the 'input' text box, giving it focus for fast data entry!<form>
for more details), as the form really controls this setting over all its child 'input' fields. But often you will have a 'form' with default settings and want to override them in each form field. The two most difficult ones to manage are "autocomplete" and "novalidate". In general, to summarize, the code samples above showcase my "best practices" and recommendations for how each field should use these two attributes.see also <del>
<p>Did you know my favorite pet is a <del>dog</del> <ins>cat</ins>.</p>
Did you know my favorite pet is a dog cat?
<ins>
) will often follow the deleted one (<del>
) to indicate a replacement of new text for the deleted one and to emphasize the change.
<isindex prompt= "cats" action="http://google.com/" />
This is some <i>italic</i> text.
<p>Press <kbd>ctrl</kbd> + <kbd>v</kbd> to paste text in Windows.</p>
Press ctrl + v to paste text in Windows.
<code>
, <var>
, and <samp>
in that 'kdb' formats text to represent abstract computer programs, keys, equations, or ideas.
<keygen id="securekey1" name="securekey1" challenge="abc123" keytype="DSA"
keyparams="somekeygenstring" />
<form id="formlabel" name="formlabel" method="post" action="#" title="Label Example" aria-label="Label Example" autocomplete="off" autocapitalize="off" spellcheck="false">
<fieldset id="formlabel_fieldset1" name="formlabel_fieldset1" form="formlabel" style="background-color:#fff;">
<legend style="background-color:#aaa;color:#fff;">Label Example</legend>
<div>
<label for="formlabel_text" title="My Text Field">My Text Field</label>
<input type="text" id="formlabel_text" name="formlabel_text" size="20" value="" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" placeholder="Enter text here..." title="Enter Text" aria-label="Text" tabindex="0" />
</div>
</fieldset>
</form>
<input>
, <select>
, and <textarea>
examples in this HTML5 list.
<layer id="mylayer">Some text content</layer>
see <fieldset>
<form id="legendform" name="legendform" action="#" method="post" aria-label="Login">
<fieldset id="legendfieldset" name="legendfieldset" form="legendform">
<legend style="background-color:#ccc;color:#fff;">Login</legend>
<p>
<label for="legendinput1" title="Username">Username: </label>
<input type="text" aria-label="Username" id="legendinput1" name="legendinput1" size="20" maxlength="10" value="" title="Username" tabindex="0" autocomplete="username" />
</p>
<p>
<label for="legendinput2" title="Password">Password: </label>
<input type="password" aria-label="Password" id="legendinput2" name="legendinput2" size="20" maxlength="10" value="" title="Password" tabindex="0" autocomplete="new-password" />
</p>
<p><button id="legendsubmit1" aria-label="Submit" aria-pressed="false" title="Login" tabindex="-1" disabled="disabled" aria-disabled="true">Login</button></p>
</fieldset>
</form>
also see <dl> and <nav>
I have combined the three main elements that control lists below: <ul>
, <ol>
, and <li>
.
There are three main "types" of lists: Unordered <ul>
, Ordered <ol>
, and Description <dl>
. We will demonstrate the first two here. Description lists <dl>
are shown elsewhere as they have unique sub-elements and perform a slightly different role in HTML. You may also see how to style unordered lists to build a "menu" in the <nav>
section of this page.
Shown below are examples of "unordered" and "ordered" lists. Both types use the 'li' child element to hold "list items". Unordered lists can be in any order, so their bullets or icons are generic types. Their list items can be arranged in any order. Ordered lists are numbered in an ordered sequence. I have also included "nested" lists below so you can see how nested lists work, and how the bullets change in style using the browsers default bullet styles.
<ul id="unorderedlist1">
<li>List item 1 : Level 1</li>
<li>List item 2 : Level 1</li>
<li>List item 3 : Level 1
<ul>
<li>List item 1 : Level 2</li>
<li>List item 2 : Level 2</li>
<li>List item 3 : Level 2
<ul>
<li>List item 1 : Level 3</li>
<li>List item 2 : Level 3</li>
<li>List item 3 : Level 3</li>
</ul>
</li>
</ul>
</li>
</ul>
<ol id="orderedlist1">
<li>List item 1 : Level 1</li>
<li>List item 2 : Level 1</li>
<li>List item 3 : Level 1
<ol>
<li>List item 1 : Level 2</li>
<li>List item 2 : Level 2</li>
<li>List item 3 : Level 2
<ol>
<li>List item 1 : Level 3</li>
<li>List item 2 : Level 3</li>
<li>List item 3 : Level 3</li>
</ol>
</li>
</ol>
</li>
</ol>
<nav>
for an example of using ARIA when lists are used as menus). These designs allow you to use unordered lists to display a styled set of navigation buttons in your web pages. In this case, you may use CSS to have their bullets removed, their margins and padding reset, and their block-level design altered to fit into custom menu designs or buttons at the top of your web page. In this case, the list item role has changed and you are using lists for a new "menu" and "menuitem" role in the web page. When you use lists for menus, you need to tell screen readers their semantic purpose has changed using ARIA. So visit the 'nav' element area mentioned above in this page for an example of how best to do that.also see <style>
A 'link' element is a non-visual (invisible) element that resides inside the <head>
element of a typical web page. Below I have listed a rich set of <link>
code examples and the many ways you can use this element to enhance your website. Note that I have added the right mix of attributes to the code examples below, so you can cut-and-paste my code and get up and running fast knowing that my 'link' examples will work well in most browsers. You just need to replace the "href" URL values and other element attributes with your own values, in most cases.
Always include a "favicon.ico" link your website!
<link rel="shortcut icon" href="favicon.ico" />
This example below demonstrates the two most important use cases for the 'link' element in websites today: External CSS style sheets. Always include links to external style sheets in your website! Why? External style sheets are cached for days, weeks, or months by the browser and control the look-and-feel of thousands of pages in your websites, unlike their less efficient cousins, "embedded" styles using the <style>
tags and "inline" styles in elements.
<link media="print" rel="stylesheet" type="text/css" href="print.css?v=1.0.0.1 />
<link media="screen" rel="stylesheet" type="text/css" href="style.css?v=1.0.0.1" />
If you deliver news feeds of your articles or blog, you can link to your RSS XML file using the 'link' element below.
<link rel="alternate" type="application/rss+xml" title="RSS" href="rss.xml" />
Add resource prefetch call below to preload assets in other pages you hope users will access when they visit a new web page. These files will be cached, but implementation of the call is optional for the browser as these are flagged as low-priority. Note: Browser support of this feature is limited. See my recommendations below for more details.
<link rel="prefetch" href="someresource.jpg" />
Add resource prerender call below to preload complete web pages and all their associated resources you hope users will access after the viewing the current web page. These files will be cached, but implementation of the call is optional for the browser as these are flagged as low-priority. If this feature is enabled, the browser will "switch" the page to the new page already rendered. Note: Browser support of this feature is limited. See my recommendations below for more details.
<link rel="prerender" href="somewebpage.html" />
The new "rel=preload" attribute works much like the "prefetch" and "prerender" types, except "preload" forces download of individual files (often style sheets) into the cache the minute the browser is available to do so. (i.e. its not optional, unlike with the other two types). I discuss how and why these preload features are used in more detail in my recommendations below.
Use this version to add resource preload calls below to files you hope users will access after viewing the current web page. Unlike "prefetch" and "prerender", "preload" types must be downloaded and cached. An optional JavaScript "hack" below allows you to preload files in the current page and use them, as well, using a "media=print" to "screen" trick. Note: Browser support of this feature is limited and relies on JavaScript to work.
<link rel="stylesheet" href="style.css" media="print" type="text/css" onload="this.media='screen';this.onload=null;" />
Use this version to add resource preload calls below to files you hope users will access after the viewing the current web page. Unlike "prefetch" and "prerender", "preload" types must be downloaded and cached. An optional JavaScript "hack" below allows you to preload files in the current page and use them, as well, using a "rel=preload" to "stylesheet" trick. Note: Browser support of this feature is limited and relies on JavaScript to work. There is a fallback "noscript" for older browsers added.
<link rel="preload" href="styles.css" as="style" type="text/css" onload="this.onload=null;this.rel='stylesheet'" />
<noscript><link rel="stylesheet" href="styles.css" type="text/css" /></noscript>
Use this version to add resource preload call below to files you hope users will access after the viewing the current web page. Unlike "prefetch" and "prerender", "preload" types must be downloaded and cached. This version only caches the file, but does not trick the browser into viewing it in the current web page. Note: Browser support of this feature is very limited.
<link rel="preload" as="style" href="style.css" />
If you prefer to use CDN's (Content Delivery Networks) to deliver your CSS files (Bootstrap), you can use this version of the 'link ' element below that is designed to do just that. This version also demonstrates the use of the new "integrity" attribute that some CDN's require and which prevents "cross-origin" rejection by some browsers. Without this encrypted key value, some CDN servers or browsers might not allow you to access their server or files.
<link rel="stylesheet" href="https://cdn.com/cssfile.css" onerror="this.onerror=null;this.href='local.css';" referrerpolicy="no-referrer" crossorigin="anonymous" integrity="sha384-..." />
You can help search engines know the "preferred" URL design to use for all your web pages, using the "canonical" version of the 'link' element, as shown below. Notice in the example below, I am telling the search engines I want all links into my website to use the "https://" version or secure URL version, and without the "www" subdomain added.
<link rel="canonical" href="https://mitchellstokely.com/" />
Like "canonical" links, this "DNS prefetch" link version is also a new feature and optional. There is no guarantee it will help improve anything in your website. If it does work, it just attempts to establish connections faster with external URL's and resources online and solve DNS resolutions quicker. Note the use of the "missing prefix" URL (href="//..."). This tells the external web resource to pick either "http" or "https" for the correct prefix. Also, remember to add an ending "/" slash to the end of URL's as it often means one less call to the server!
<link rel="dns-prefetch" href="//mitchellstokely.com/" />
Like "prefetched" links, this "preconnect" version is also a new feature and optional. There is no guarantee it will help improve anything in your website. It attempts to locate available browser connections early with foreign servers and connect with those external resources before they are needed. This can make for a slightly faster web page display when you use lots of external dependencies.
<link rel="preconnect" href="//maxcdn.bootstrapcdn.com/" crossorigin="anonymous" />
<style>
) and "inline" element styles (<span style="color:blue;">my text</span>
) simply because external styles downloaded to the browser are cached for every page in your website and affect all web pages, not just one. Often inexperienced developers use inline or embedded styles and forget about externally linked CSS sheets. They assume they are slower, inferior, antiquated, or difficult to manage when the opposite is true. They then lose out on valuable, reliable, proven technology that is far superior to anything built today. Links to multiple external CSS files also download in parallel to each other in a very quick fashion in most browsers, so there are few delays. Browsers have been doing this for over 20 years. Unlike large libraries of scripts, linked CSS often has a very tiny footprint and so has very little affect on page rendering or paint delays, simply because modern browsers manage these downloads very effectively and have been for decades. Once your CSS files are downloaded, they are cached and indexed in browser folders, allowing future page views of your site to be rendered and painted in the browser very quickly.
<link rel="preload" as="style" href="style.css" />
<link rel="stylesheet" href="style.css" media="print" type="text/css" onload="this.media='screen';this.onload=null;" />
<link rel="preload" href="styles.css" as="style" type="text/css" onload="this.onload=null;this.rel='stylesheet'" />
<noscript><link rel="stylesheet" href="styles.css" type="text/css" /></noscript>
<head>
of your web page affect the cascade order of similar style rules on elements? It is an important question. It turns out it DOES in modern HTML5 browsers, but did NOT in many older browsers (pre-2010)! Why? Older browsers used to have a very good rule the W3C used to require they follow. It basically said that no matter where external <link>
styles appear in the <head>
of your web page, "embedded" or <style>
CSS was always last in the order set inside the browsers cascade memory, not in your web page. In other words, embedded styles always cascaded over linked styles using the same selectors, even if you placed external linked CSS AFTER embedded CSS in your web pages. Linked external CSS elements always came before embedded CSS in the memory of the browser, no matter what physical order your code used. This is NOT the case in newer HTML5 browsers, I found out. This might be a subtle issue to you, but if you stack lots of "element" style rules in your external and internal style sections of your web page 'head' element, rules that use the exact same selectors, if you do not order your linked external CSS elements correctly then you might see some cascade over others, unexpectedly in newer HTML5 browsers! Order of styles now matters in your pages, where in the past it did not. The reason newer HTML5 browsers now strictly honor specific style sheet "source order" in the "head" of your page, regardless of linked vs embedded types, is because HTML5 has gotten lazier and looser in defining such things. In other words, be careful in the order you place linked and embedded styles, as they do matter today. Embedded sheets no longer have higher source order over linked sheets, as they did in the past. To match old and new browsers so they both work the same using external and embedded sheets, ALWAYS add your linked sheets (<link>
) above your embedded ones (<style>
) in the head of your page.
<!--[if IE 8 ]>
<link media="screen" rel="stylesheet" type="text/css" href="/styles/ie8only.css" />
<![endif]-->
<!--[if IE 9 ]>
<link media="screen" rel="stylesheet" type="text/css" href="/styles/ie9only.css" />
<![endif]-->
<listing>This element shows content that used to act like preformatted text.</listing>
See also <header>, <nav>, <footer>, <section>, <article>, and <aside>
<main id="main" aria-label="Main Content" >Main</main>
* A typical web page structure is shown above.
see <area>
<p>(rollover the image map below)</p>
<img src="images/www.jpg" width="255" height="200" usemap="#mymap" loading="lazy" alt="World Wide Web Image" title="World Wide Web Image" />
<map id="mymap" name="mymap" title="World Wide Web Image Map">
<area shape="circle" coords="80,130,40" alt="What is the World Wide Web?" title="What is the World Wide Web?" href="https://en.wikipedia.org/wiki/World_Wide_Web" target="_blank" rel="noreferrer nofollow noopener">
</map>
<ol>
<li><a href="https://en.wikipedia.org/wiki/World_Wide_Web" title="What is the World Wide Web?" target="_blank" rel="noreferrer nofollow noopener">What is the World Wide Web?</a></li>
</ol>
(rollover the image map below)
<p>Make sure you <mark>highlight every important topic</mark> listed in the document.</p>
Make sure you highlight every important topic listed in the document.
mark {
display: inline;
background-color: yellow;
color: black;
}
<marquee behavior="scroll" direction="right" scrolldelay="85" style="color:red;">This is some text that should scroll across the page</marquee>
<button type="menu" menu="contextmenu" title="Click to Show a Context Menu">Show Context Menu</button>
<br /><br />
<menu type="context" id="contextmenu">
<menuitem>Menu Item 1</menuitem>
<menuitem>Menu Item 1</menuitem>
<menuitem>Menu Item 1</menuitem>
</menu>
Below is a button that when "clicked" would normally trigger a context menu to appear. Instead, in most browsers, nothing will happen. You may just see a "box of text" which my style sheet system has tried to style on the 'menu' element so it looks presentable. But its not the toggled "context menu" you expect, as 'menu' elements are not currently supported in most browsers.
<nav>
element with lists, anchor links, and CSS styling, instead.see <html>
<html>
element for a full description.also see <progress>
<p>
<meter id="meter1" min="0" max="10" value="2" title="Car Fuel Left as a Number" aria-label="Car Fuel">2 out of 10</meter>
<label for="meter1" title="Car Fuel Meter">Car Fuel Left (number)</label>
</p>
<p>
<meter id="meter2" value="0.8" title="Truck Fuel Left as a Percent" aria-label="Truck Fuel">80%</meter>
<label for="meter2" title="Truck Fuel Meter">Truck Fuel Left (percentage)</label>
</p>
<multicol col="3">
<p>Text column one</p>
<p>Text column two</p>
<p>Text column three</p>
</multicol>
Text column one
Text column two
Text column three
See also <header>, <main>, <footer>, <section>, <article>, and <aside>
I have included a styled menu using an "unordered" list to demonstrate how you might use the 'nav' element in your website. 'nav' elements do not create menus or any sort of navigation. They are just placeholders for those things. Keep in mind its best to place the 'nav' inside the 'header' element (as shown below) so everything is managed in a clean, manageable, semantic HTML structure.
<style>
/* Here is a very basic menu style I created to show you what is possible inside a "nav" element. */
.nav_menu {
display: block;
width: auto;
height: auto;
padding: .5em 1em;
border: 1px solid #ccc;
margin: .1em;
text-align: center;
min-width: 20em;
color: #000;
background:#fff;
}
.nav_ul {
display: block;
width: 100%;
height: auto;
margin: 0;
padding: 0;
border: none;
background-color: #bbb !important;
text-align: left;
list-style: none;
}
.nav_li {
display: inline-block;
width: 8em;
height: auto;
margin: 0 2px 0 0;
padding: 0;
border: none;
background: none !important;
list-style: none;
text-align: center;
vertical-align: middle;
}
.nav_a,
.nav_a:link,
.nav_a:visited {
display: inline-block;
width: 100%;
height: auto;
margin: 0;
padding: .25em 0em;
background-color: #999 !important;
border: none;
text-decoration: none;
text-align: center;
vertical-align: middle;
color: white;
}
.nav_a:hover,
.nav_a:focus,
.nav_a:active {
background-color: #666 !important;
}
.nav_div {
display:block;
width:auto;
height:auto;
padding:.5em 1em;
border:1px solid #ccc;
margin:.1em;
text-align:center;
min-width:20em;
color:#999;
background:#eee;
}
</style>
<div class="nav_div">
Header
<nav id="nav" aria-label="Navigation" class="nav_menu">
Nav
<ul id="menu" role="menu" aria-label="Main Menu" class="nav_ul"><!--removes space between inline-block elements
--><li role="menuitem" class="nav_li"><a href="#" aria-selected="true" class="nav_a">Home</a></li><!--
--><li role="menuitem" class="nav_li"><a href="#" class="nav_a">Page 1</a></li><!--
--><li role="menuitem" class="nav_li"><a href="#" class="nav_a">Page 2</a></li><!--
--><li role="menuitem" class="nav_li"><a href="#" class="nav_a">Page 2</a></li><!--
--></ul>
</nav>
</div>
<div class="nav_div">Main</div>
<div class="nav_div">Footer</div>
* A typical web page structure is shown above.
<header>
element. Typically, the 'nav' element contains "navigational" elements or menu items that define the main links to other web pages located within a typical web application. Note: The 'nav' element does NOT create actual navigation or menus, it just holds such elements you create. In HTML5, the 'nav' element is part of a set of new structural page elements that define the overall layout of most HTML5 website pages designed today (<header>, <main>, and <footer>, etc.).
<nobr>This text should not wrap</nobr>
see <embed>
<embed>
element for a full description.see <frameset> and <frame>
<frameset cols="50%,50%">
<frame src="https://www.w3.org/TR/html4/present/frames.html#h-16.2.1" />
<frame src="https://www.w3.org/TR/html4/present/frames.html#h-16.2.2" />
<noframes>
<p>This frameset includes two page views of the W3C websites on frames.</p>
</noframes>
</frameset>
* If you do not see anything below, then the 'frameset, 'frame', and 'noframes' elements are not supported in your browser.
Many people use 'noscript' to provide alternative content when JavaScript is turned off or unavailable in a web browser. But I like to use it as an "alert box" with a message for users to turn on JavaScript or upgrade their browsers. I like to use these message box at the top of every web page I build. Again, the 'noscript' element and its content is completely hidden in most JavaScript-supporting browsers but shown when they do not support scripting. As a BONUS, I also like to use a matching hidden 'div' alert box for browsers that do not support CSS style sheets, as well. Below is an example of both alert boxes. The style sheet version doesn't have a special element like 'noscript', but uses a simple style with "display:none" on it. Any old browser, like Internet Explorer 1-2 or Netscape 1-3, that does not support style sheets ignores the "display:none" that hides the 'div' content box and shows the full message, alerting them to get a new web browser. For testing purposes, I'm revealing the messages below without the 'noscript' element so you can see what it looks like. But the code snippet below has all the right code. You can cut-and-paste it into your project. Both boxes will be hidden permanently from all other browsers, until triggered and viewable in the non-supporting ones.
<noscript>
<div style="border:1px solid red;margin:.5em;padding:1em;background:white;" role="alert" aria-label="Alert Message: No JavaScript Support">
<strong>Alert! You may have turned off JavaScript in your web browser, or it does not support scripting.</strong> As a result, some features in this website may not function correctly. Our website works best using one of the following modern web browsers: <strong><a href='https://www.google.com/chrome/' title="Download Google's Chrome Web Browser" target="_blank" rel="noreferrer nofollow noopener">Chrome</a>, <a href='https://www.mozilla.org/en-US/firefox/new/' title="Download Mozilla's Firefox Web Browser" target="_blank" rel="noreferrer nofollow noopener">Firefox</a>, <a href='https://www.microsoft.com/en-us/edge' title="Download Microsoft's Edge Web Browser" target="_blank" rel="noreferrer nofollow noopener">Edge</a>.</strong>
</div>
</noscript>
<div style="border:1px solid red;margin:.5em;padding:1em;background:white;" role="alert" aria-label="Alert Message: No CSS Support">
<strong>Alert! Your web browser does not fully support Cascading Style Sheets!</strong> Our website works best using one of the following modern web browsers: <strong><a href='https://www.google.com/chrome/' title="Download Google's Chrome Web Browser" target="_blank" rel="noreferrer nofollow noopener">Chrome</a>, <a href='https://www.mozilla.org/en-US/firefox/new/' title="Download Mozilla's Firefox Web Browser" target="_blank" rel="noreferrer nofollow noopener">Firefox</a>, <a href='https://www.microsoft.com/en-us/edge' title="Download Microsoft's Edge Web Browser" target="_blank" rel="noreferrer nofollow noopener">Edge</a>.</strong>
</div>
also see <param>
<object id="object1" alt="object: Psychedelic Video" data="video1.mp4" type="video/mp4" style="width: 320px;height: 240px;outline: none;border:1px solid #bbb;" loop="false" title="Psychedelic Video" aria-label="Object File: Psychedelic Video">
<!-- "params" are optional but supported by some older browsers -->
<param name="movie" value="video1.mp4" />
<param name="type" value="video/mp4" />
<param name="play" value="false" />
<param name="loop" value="false" />
<param name="quality" value="high" />
<param name="autoplay" value="false" />
Sorry, your browser does not support this video.
</object>
Below is an example using the 'object' tag to play a movie file. Depending on your browser and the plug-in or player supported, you should see a "MPEG-4" file play. If you do not, it is because this video format or codec is not supported by your browser or its player. Note: Internet Explorer browser may not play this specific video codec, or may have ActiveX disabled.
see <li>
<li>
element for a full description.see <select>
The 'option' and 'optgroup' elements are children of the 'select' element. Shown below is an example of these elements when using the 'select' element form control.
<form id="formoption" name="formoption" method="post" action="#" title="Option and Option Group Example" aria-label="Option and Option Group Example" autocomplete="off" autocapitalize="off" spellcheck="false">
<fieldset id="formoption_fieldset1" name="formoption_fieldset1" form="formoption" style="background-color:#fff;">
<legend style="background-color:#aaa;color:#fff;">Option and Option Group</legend>
<div>
<select id="formoption_select1" name="formoption_select1" size="1" title="Select a Fruit" aria-label="Fruit" tabindex="0">
<option value="" selected="selected">-- select a fruit --</option>
<option value="strawberry">Strawberry</option>
<option value="banana">Banana</option>
<option value="grape">Grape</option>
<optgroup label="Apple" role="group">
<option value="apple_reddelicious">Red Delicious</option>
<option value="apple_macintosh">Macintosh</option>
<option value="apple_green">Green</option>
</optgroup>
</select>
</div>
</fieldset>
</form>
<option value="{my option value}">My Option Text</option>
.<select>
element section for more details about this issue and the 'select element in general.In the example below, I have added the new HTML5 'output' element (last box) in combination with the new "range" and "number" HTML5 form controls. This allows a user to change the "range" and "numeric" input types, have a JavaScript event ("oninput") on the 'form' element add the values together, then have it post the mathematical result to the 'output' element box. Browser support for this feature is still weak.
<form id="formoutput" name="formoutput" method="post" action="#" title="Input Example" aria-label="Input Example" autocomplete="off" autocapitalize="off" spellcheck="false" oninput="formoutput_output1.value=
parseInt(formoutput_range.value)+
parseInt(formoutput_number1.value)">
<fieldset id="formoutput_fieldset1" name="formoutput_fieldset1" form="formoutput">
<legend style="background-color:#aaa;color:#fff;">Output Example</legend>
<div>
<input type="range" id="formoutput_range" name="formoutput_range" value="50" min="0" max="100" minlength="1" maxlength="3" tabindex="0" autocomplete="off" title="Slide the Range Indicator" aria-label="Slide the Range Indicator" /> +
</div>
<div>
<input type="number" id="formoutput_number1" name="formoutput_number1" value="0" min="0" max="100" minlength="1" maxlength="3" tabindex="0" title="Number" aria-label="Number" /> =
</div>
<div>
<output id="formoutput_output1" name="formoutput_output1" for="formoutput_range formoutput_number1" tabindex="0" value="0" title="Number Output" aria-label="Number Output"></output>
<label for="formoutput_output1" title="Output">Output</label>
</div>
<hr />
</fieldset>
</form>
<input>
for all the details). As such, it should reside inside a typical 'form' control and perform like any other input, except the unique property that a user cannot enter data into it by default. It must rely on some outside script or source to add values to it, which makes it a non-typical HTML form field element.<input>
element design). But it does not. This control should be visible, but by default, most browsers do not show any marker or visible features for 'output' until an output value appears via a JavaScript event. So, it will appear as an invisible control with no form field dimensions until some script inserts a value into it, triggering its display. In the example above, I have tried to style the 'output' to match my 'input' textbox elements, so you will see it has a border, padding and other features. But the styling turned out to be more difficult that I planned in some browsers. In most cases, you want 'output' to be simply an empty white box ready to receive values. But it's invisible with no dimensions in some browsers, initially. To address this I found you had to change the display to "block" and give it width and height. This of course defies the default "inline-block" dimensions of other form fields, which can also slide next to each other, if needed. Setting the control to block allows us to give it an appearance, but no ability to float alongside other form fields, now. But that is fine. It must act like a block-level element and drop down below any neighboring 'input' or other elements if it has to be seen. Its a fair trade-off. Again, I do not recommend this element's use, but if you do, below is a style that at least gives it an appearance in the browser:
body output,
body output:visited,
body output:hover,
body output:focus,
body output:active {
display: block;/* Defines its dimensions and thus forces its appearance. */
width: 12em;/* Defines its dimensions and thus forces its appearance. */
max-width:12em;/* Defines its dimensions and thus forces its appearance. */
height: 1.8em;/* Defines its dimensions and thus forces its appearance. */
cursor: pointer;
width: auto;
padding: .2em .2em;
padding: .2rem .2rem;
margin: 0;
border-radius: .2em;
border-radius: .2rem;
border: 2px solid #bbb;
background: #fff;
line-height: normal;
}
<p>Lorem ipsum dolor sit amet, mea enim erat id, regione iudicabit consetetur ius ex. Qui vide errem ut, ius id movet atomorum. Sit pericula definiebas ei, ex eam essent maluisset. Duis ceteros pro ut. Mei eius labore ut. Iusto facete facilisi vel id, nonumy omnium constituto ad pro. Mei in sale option.</p>
<p>Vim ei latine intellegat. Mei ea ferri suavitate. Scaevola comprehensam necessitatibus mel ad, at liberavisse signiferumque duo. Aeque tation nec ad, no sea mucius epicuri comprehensam.</p>
<p>Invenire contentiones cum cu. Nullam timeam ceteros sed ne. Et usu case eleifend, atqui malorum civibus sed ea. At eruditi inimicus repudiandae qui, quo quaeque alterum gloriatur in.</p>
Lorem ipsum dolor sit amet, mea enim erat id, regione iudicabit consetetur ius ex. Qui vide errem ut, ius id movet atomorum. Sit pericula definiebas ei, ex eam essent maluisset. Duis ceteros pro ut. Mei eius labore ut. Iusto facete facilisi vel id, nonumy omnium constituto ad pro. Mei in sale option.
Vim ei latine intellegat. Mei ea ferri suavitate. Scaevola comprehensam necessitatibus mel ad, at liberavisse signiferumque duo. Aeque tation nec ad, no sea mucius epicuri comprehensam.
Invenire contentiones cum cu. Nullam timeam ceteros sed ne. Et usu case eleifend, atqui malorum civibus sed ea. At eruditi inimicus repudiandae qui, quo quaeque alterum gloriatur in.
<br />
element between lines of text, the 'p' element wraps around a paragraph of text, creating both a new line break before and margins of spacing before and after that is collapsed into one between paragraphs. The paragraph patterns paragraph designs with text in old books. So its design comes from that original source, not the World Wide Web. Because paragraphs and the 'p' element has been around since the birth of HTML in the 1990's, this element has not changed in any of the browsers (except when it comes to how collapsing margins might work in a few) and so is very reliable.also see <object>
The 'param' element is used inside a parent 'object' tag to control its multimedia parameters. An example of these parameters using a video object is shown below.
<object id="object2" alt="object: Fireplace Video" data="video1.mov" type="video/quicktime" loop="false" style="width: 320px;height: 240px;outline: none;border:1px solid #bbb;" title="Fireplace Video" aria-label="Object File: Fireplace Video">
<param name="movie" value="video1.mov" />
<param name="type" value="video/quicktime" />
<param name="play" value="true" />
<param name="loop" value="false" />
<param name="quality" value="high" />
Sorry, your browser does not support this video.
</object>
(Above is an example using the 'object' tag. Depending on your browser and the plug-in supported, you should see a "MOV" (Apple Quicktime) video file. If you do not it is because this video format or codec is not supported by your browser.)
<img>
, <picture>
, <iframe>
, <video>
, or <audio>
elements instead for those types, and <object>
for specialized multimedia types only. Keep in mind 'object' relies on plug-ins and players to play its media, unlike the other HTML5 media types. More details below.<param />
. Do not let others convince you this is a "void" element or that this format is not compatible with HTML5, because it is.also see <img>
Below I have wrapped the 'img' element in a 'figure' element, then a 'picture' element. The 'figure' element provides a 'figcaption' or text caption for the image (not picture), assisting non-visual readers.
The 'img' element below also has a set CSS "style" attribute with variable width and height added to support the possible variable dimensions of the alternate image types assigned by the 'source' elements. It does have "width" and "height" attributes whose values are based on its default image, which the browser should only use if it defaults to its first image. But those will be ignored as each source image with different dimensions is applied.
If you see a "flowering tree" image ("webp" type) below, your browser supports one of the new alternate HTML5 image formats that the picture's 'source' element has assigned your 'img' element. If you see the "weather map" image it means your browser does not understand the WebP image type or failed the "media" viewport check in the previous 'source' element. Finally, if you see the default 'img' element's "World Wide Web" globe image ("jpg" type), the previous two image types failed and your browser only supports "jpegs".
<figure aria-labelledby="picturecaption1" style="padding: .5rem;border: 1px solid #bbb;background: #f0f0f0;width: auto;height: auto;display: inline-block;">
<picture id="picture1">
<source srcset="image.webp" type="image/webp" />
<source srcset="weather.gif" media="(min-width: 800px)" type="image/gif" />
<img id="picture1_img" style="width: auto;height: auto;max-width: 100%;" src="www.jpg" width="255" height="200" alt="image: World Wide Web" title="The World Wide Web" aria-label="Image of the World Wide Web" loading="lazy" onerror="this.onerror=null;" />
</picture>
<figcaption id="picturecaption1" style="display:block;">
"Which Image Appears?"
</figcaption>
</figure>
* Note: My host provider does not support "WebP" images I found out, so if no "flowering tree" WebP image appears, it is not the code but my host provider. :(
<source>
tag attributes supported and their role in controlling alternative images:
<plaintext>
All content after this element would show text and HTML elements as is.
<pre>
<p>Here is my sample paragraph using 'pre'.</p>
</pre>
<p>Here is my sample paragraph using 'pre'.</p>
also see <meter>
<p>
<progress id="progress1" max="100" value="40" title="Loading Bar in Minutes" aria-label="Loading Bar">40 minutes left</progress>
<label for="progress1" title="Loading Bar 1">Loading (min)</label>
</p>
<p>
<progress id="progress2" max="1" value="0.8" title="Loading Bar in Percent" aria-label="Loading Bar">80%</progress>
<label for="progress2" title="Loading Bar 2">Loading (%)</label>
</p>
<meter>
. It also falls back nicely to text inside the 'progress' tags (as shown in the code examples above) when the visual element collapses. And it supports labels. But many older browsers, IE, will not benefit from that text without the supporting graphic display, which is its hallmark. The graphics will change based on the browser and operating system of the user. The progress bar appears smaller or thinner than 'meter', in many cases. But, I recommend this element over 'meter' if you need a progress graphic element, though it's not widely supported.
Benjamin Franklin is known to have said <q cite="https://www.fi.edu/benjamin-franklin/famous-quotes" title="Famous Ben Franklin Quote">Well done is better than well said</q>.
Well done is better than well said.
Only half of the ruby elements listed here have enough support by browsers today and in the past to be useful. These three ruby elements are the ones I currently recommend you use: <ruby>
, <rt>
, <rp>
. These ruby elements are supported in many older Internet Explorer browsers and in all of the HTML5 browsers, so have the widest support in browsers today. The others are deprecated from current HTML5 browsers and never were supported in older ones. Below are some examples of how to use ruby the right way with the three ruby elements mentioned.
Here is a basic use of the ruby structure to show you how it is laid out with the 'ruby', 'rt', and 'rp' elements. I have added a few inline styles to "bold" the ruby text. If your browser supports the 'ruby' element it should place the "ruby annotation" text above the "ruby base text". The 'rp' or ruby parenthesis element below is not seen by ruby-supporting browsers, but only appears for browsers that do not support ruby. The 'rp' tags can contain any text you like, but parenthesis are common. If ruby elements are not understood in a user agent, the 'rt' text drops to the right of the foreign language text with the 'rp' text around it.
<p>
<ruby style="font-weight:bolder;">
ruby base text
<rp style="font-weight:normal;"> (</rp>
<rt style="font-weight:normal;">ruby annotation</rt>
<rp style="font-weight:normal;">) </rp>
</ruby>
</p>
ruby base text
In this example, I am doing a translation type of ruby annotation. Notice the 'ruby' element wraps around everything and is an inline element, so part of the sentence flow. I have added the "xml:lang" for Japanese to help the browser render the right characters, though it is not required.
<p>This is how we say
<ruby xml:lang="ja">
ようこそ
<rp> (</rp>
<rt>welcome</rt>
<rp>) </rp>
</ruby>
in Japanese.
</p>
This is how we say ようこそ in Japanese.
In this example, I am translating text with ruby again, but translating a full sentence this time. In this ruby design, it might be better to drop the text translation below the Japanese text, which you can do with plain CSS styles. In the second example, I have used plain CSS styling to do change positioning of the ruby annotation to the bottom of the language text. Many use the "ruby CSS properties" to do this. The problem is, these special ruby properties have almost no support in older IE browsers and are sketchy in others.
<p>
<ruby xml:lang="ja">
東京 に 行き たい。
<rp> (</rp>
<rt>I want to go to Tokyo</rt>
<rp>) </rp>
</ruby>
<br />
</p>
東京 に 行き たい。
<p>
<ruby xml:lang="ja" style="position:relative;">
東京 に 行き たい。
<rp style="position:relative;top:2em;"> (</rp>
<rt style="position:relative;top:2em;">I want to go to Tokyo</rt>
<rp style="position:relative;top:2em;">) </rp>
</ruby>
<br />
</p>
東京 に 行き たい。
In this example, I am combining "pronunciation" of the Chinese symbol(s) with an added ruby "translation", as well. To manage all this code block, I am also nesting two 'ruby' elements together, plus the added translation after it, so I can separate out the two languages better. Notice that "Welcome" sits above the nested 'ruby' pronunciation set. That is because I used two 'rt' elements. In many cases, the browser will stack the second 'rt' above the previous ruby set that it relates to. As bad as that may look, try and use the browsers "default ruby positioning" and avoid changing it. In older browsers that do not support ruby, the text will appear to the right with parenthesis.
<p>
<ruby xml:lang="cn">
<ruby xml:lang="cn">
欢迎<rp> (</rp>
<rt>Huānyíng</rt>
<rp>) </rp>
</ruby>
<rp> (</rp>
<rt>Welcome</rt>
<rp>) </rp>
</ruby>
</p>
欢迎
Here is an example of the above ruby code but using the new HTML5 ruby elements (<rb>
, <rbc>
, <rtc>
) and a newer ruby CSS property, both of which are now deprecated according to HTML5 groups online. Again, you should avoid these elements as they have almost no browser support. Even if they work ok for your browser, remember no other browsers prior to 2010 or even later will support them, much less many newer ones.
<p>
<ruby xml:lang="cn">
<ruby xml:lang="cn">
<rbc>
<rb>欢迎</rb>
<rp> (</rp>
<rt>Huānyíng</rt>
<rp>) </rp>
</rbc>
</ruby>
<rtc xml:lang="en" style="ruby-position: under;">
<rp> (</rp>
<rt>Welcome</rt>
<rp>) </rp>
</rtc>
</ruby>
</p>
<ruby>
or "ruby" (<rt>
or "ruby translation" (<rp>
or "ruby parenthesis" (<rb>
<rbc>
<rtc>
<ruby xml:lang="ja">
for Japanese. You can also style ruby 'rt' text to float left, right, above, or below foreign text, though CSS support for special properties for ruby do not have wide support (example: "ruby-position: under"). Internet Explorer has almost no support for these properties. If you must position or style ruby child elements, I recommend you stay with the default browser formats or use a CSS class and say CSS "position:relative" and other traditional CSS properties to align the text as you need. Finally, there were some old properties on 'rt' (like "RBSPAN=3", etc.) and other element attributes no longer supported. So, stay with CSS when changing the design of ruby elements.<ruby>
, <rt>
, <rp>
) and avoid the ruby elements, as well as avoid the special ruby CSS properties, due to lack of browser support.
The store will be closed on <s>9/19/2021</s>. <strong>Now we are open for another month!!</strong>
<strike>
element, which has been fully deprecated in HTML5 and was a design element only, much like <small>
and <big>
elements. But the 's' element is more often confused with the <del>
element, which is supported and also uses a "strikethrough" on text. What is the difference then?
<p>When I pressed the <kbd>Ctrl</kbd> key, my computer said <samp>"Hello World"</samp>.</p>
When I pressed the Ctrl key, my computer said "Hello World".
<code>
, <kbd>
, and <pre>
in that 'samp' formats text to represent abstract computer values.A 'script' element is a non-visual (invisible) element that is used to download and run JavaScript in your website. Below I have listed a rich set of <script>
code examples and the many ways you can use this element to enhance your website with scripts. Note that I have added the right mix of attributes to the code examples below, so you can cut-and-paste my code and get up and running fast knowing that my 'script' examples will work well in most browsers. You just need to replace the "src" URL values with your own values, in most cases.
This example below demonstrates one of the two main use cases for the 'script' element in websites today: "External" JavaScript Files and "Embedded" JavaScript Code (or "internal"). I prefer you use this "external" file version of the 'script' element. Why? External style sheets are globally cached for days, weeks, or months by the browser and control the scripting needs of thousands of pages in your websites, unlike their less efficient cousin, the "embedded" script tag which loads script code for just a single web page. The latter type is wasteful and increases the bandwidth needed to support millions of downloads of JavaScript code from your server over years and years. Note: You typically add these links to external JavaScript files inside the <body>
element at the bottom of your web page. This forces the browser to delay importing in the JavaScript file until after the main HTML markup in the web page is downloaded and parsed. Note the use of "defer" which helps preload then pause the script until the HTML is rendered.
<script src="myscript.js" type="text/javascript" defer="defer"></script>
If you prefer to use CDN's (Content Delivery Networks) to deliver your script files, you can use this version of the 'script' element below that is designed to pull down JavaScript libraries from a 3rd party content provider. This one is free and available to anonymous users. Note: You typically add script downloads like this in the <body>
of your web page at the bottom. This forces the browser to load the script last after downloading and rendering the HTML content. Note that I have added "defer" to force the script to pause until all HTML is rendered. I have also added a preprocessing 'link' for the external CDN URL, reducing the time needed to connect to the CDN's domain (see my section on <link>
).
<link rel="preconnect" href="//code.jquery.com/" crossorigin="anonymous" />
<script
src="https://code.jquery.com/jquery-3.6.0.js"
integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
crossorigin="anonymous"
type="text/javascript"
referrerpolicy="no-referrer"
defer="defer">
</script>
I do not recommend you use this "embedded" script element, as it only allows your scripts to affect a single web page. Unless you truly need a script that only affects a single page in your website, I recommend you use the "external" script version above, instead.
Note: If you must use these single-page script blocks, I have added an XML-friendly, "no JavaScript support" friendly "CDATA" version to the "embedded" code example below, which is superior to any embedded 'script' coding block you will find online. It supports your page scripts in XHTML 1.1, XHTML5, XML parsers, browsers with no JavaScript support, JavaScript disabled for security reasons, or browsers with full support for JavaScript. Use this version below if you have to use "embedded" scripting. Note: You typically add script blocks in the <head>
of your web page. This forces the browser to load the scripts first before downloading HTML content and should only contain scripts that need to be fully preloaded first and which directly affect or control HTML right after it is rendered. Note: The "strange" CDATA code that wraps around the scripts is "extra" code designed to hide/support JavaScript code in the tags from XHTML, XML parsers, and older non-supporting JavaScript browsers (see my recommendations below for a full explanation).
<script type="text/javascript">
<!--//--><![CDATA[//><!--
alert('hello world!');
//--><!]]>
</script>
<head>
section of your web page or at the bottom of the <body>
element. Each version of the 'script' element uses different strategies, however, as each type has a different purpose.
<script type="text/javascript">
<!--//--><![CDATA[//><!--
// put your scripts here
//--><!]]>
</script>
Some History on this Strange Code Above: Going back to the 1990's, you were allowed to place these HTML comments "<!--" and "-->" inside the 'script' element to hide JavaScript text from non-script supporting browsers, which would recognize the HTML comments and hide the scripts. Supporting JavaScript browsers back then would ignore them and execute the scripts. Why? These 'script' and 'style' elements read anything inside the tags as character data or CDATA, which means no HTML is recognized inside the tags. HTML comments are still HTML so ignored by them. So, most browsers that supported JavaScript back then ignored these HTML comments, as anything in these elements was considered CDATA, allowing JavaScript to execute safely for them. By the way, these now defunct older non-JavaScript supporting browsers included IE 1-3.01 and Netscape 1-1.4. For them, the HTML comments meant the script code was safely commented out. These same comment markers above, however, had to be redesigned to support even more scenarios of non-JavaScript supporting agents over time beyond just these older HTML4 browsers. Added to this problem has been XHTML and XML parsers, which do not know the code between these tags is just CDATA. Such parsers would blow up if they parsed JavaScript that contained any XML entities or markers. Many of these XML-friendly parsers did not run JavaScript or scripting parsers at all. To fix the code for them, I had to expand the comments above to force those parsers to ignore the scripting code, as well. And so that is how I came to develop the solution above. In the HTML5 browser world today, nearly all browsers known now support JavaScript. But adding the comments and safety code above allows you to still support a range of very old non-JavaScript supporting browsers, XHTML, and XML parsers combined, should you need to share your code or web pages with any of these parsers or browsers. They will not blow up now when encountering your JavaScript code using the comments above. The code above is completely safe to use now in newer, more modern HTML5 browsers. But when used, it will make sure your JavaScript blocks are ignored in XML parsers and non-JavaScript supporting older browsers alike.Below are a few things I recommend in trying to preload 'script' files and which I have added in my code examples above to help you squeeze the most performance from your 'script' tags using JavaScript. In the code above, I have added the attributes and code that will work best, so you can cut-and-paste the code as is, knowing I have added just what you need in your HTML5 code to improve a little on download times. But, below are all the dirty details of why I elected to use the code above:
document.addEventListener('DOMContentLoaded',
() => alert("DOM ready after defer!"));
See also <header>, <nav>, <main>, <section>, <article>, and <aside>
<section id="content" aria-labelledby="mainheading1">
<h1 id="mainheading1">Section</h1>
<p>Web page content goes here...</p>
</section>
Web page content goes here...
* A typical web page structure is shown above.
see <option> and <optgroup>
see <form> for more details using <select> in forms
Shown below is a complete code sample of the <select> element, which you can copy-and-paste into your web project. It has a rich set of attributes I recommend you use for each scenario. The visual design for this form is shown below the code. With these examples you have a complete set of code you can use in your web forms.
<form id="formselect" name="formselect" method="post" action="#" title="Select Example" aria-label="Select Example" autocomplete="off" autocapitalize="off" spellcheck="false">
<fieldset id="formselect_fieldset1" name="formselect_fieldset1" form="formselect" style="background-color:#fff;">
<legend style="background-color:#aaa;color:#fff;">Select</legend>
<div>
<label for="formselect_select1" title="Single Select">Single Select Label:</label><br />
<select id="formselect_select1" name="formselect_select1" size="1" title="Select an Item" aria-label="Single Select" tabindex="0">
<option selected="selected" value="">-- select a fruit --</option>
<option value="strawberry">Strawberry</option>
<option value="banana">Banana</option>
<option value="grape">Grape</option>
<optgroup label="Apple" role="group">
<option value="apple_reddelicious">Red Delicious</option>
<option value="apple_macintosh">Macintosh</option>
<option value="apple_green">Green</option>
</optgroup>
</select>
</div>
<hr />
<div>
<label for="formselect_select2" title="Multiple Select">Multiple Select Label:</label><br />
<select id="formselect_select2" name="formselect_select2" size="6" title="Select One or More Items" aria-label="Multiple Select" multiple="multiple" aria-multiselectable="true" tabindex="0">
<option value="" selected="selected">-- select multiple numbers --</option>
<option value="1">one</option>
<option value="2">two</option>
<option value="3">three</option>
<option value="4">four</option>
<option value="5">five</option>
<option value="6">six</option>
<option value="7">seven</option>
<option value="8">eight</option>
<option value="9">nine</option>
<optgroup label="ten to twenty" role="group">
<option value="10">ten</option>
<option value="20">eleven</option>
</optgroup>
</select>
</div>
</fieldset>
</form>
<form>
: Element Around Your 'select' Elements: When you wrap a form tag around a 'select' control, it tells the browser your 'select' is associated with a specific form "id" value and will only submit the field elements associated with that control. If you have multiple selects and form fields to submit to a web page, it is crucial you know what select belongs with which form. You can still place the element outside a form if you give it a 'form={id}' attribute with a value associated with a specific form "id". In that case, it will be submitted with all the fields inside that specific form, though it might lie outside the form. However, I do not recommend you move form controls outside of a form, as some older browsers may fail to send the right data when submitted.<label>
Element with Your 'select' Element: Try and use the 'label' element before your 'select' tag, then add the "for" attribute with a value that matches the select's 'id' value to associate the two together. This links the label to the form field and allows the browser, search engines, and screen readers to connect the two, adding semantic meaning. Often, the browsers will float the label text above the select control. But I have added a break after it as select boxes tends to float right as an inline-block element (see my code samples above for examples of labels and select controls). "clicking" on the label's text auto-selects most form fields, but not in the case of select. However, giving your 'select' element a label is still important. Be sure to add a descriptive 'title' attribute to your label, as well.<option value="{value}">>My Option</option>
. Often the text name inside the 'option' element is the same as "value" (like "yes"/"no", "on"/"off", etc.). But it can also be different from the "value". This is what is sent to the server as data, and part of the "name-value" attribute pair sent to the server from your form control when the 'select' is submitted. In the case of a 'select' element set as "multiple=multiple", each selected "option" will always send the same 'select' element "name" value for all the 'option' "values" selected. So make sure each 'option' "value" is unique, as you have to loop through the same array of names to get each value selected. The data for multiple select choices sent to the server will appear like this: myselect=1&myselect=2&myselect=3. IMPORTANT: If the "value" attribute in 'option' is omitted, the value is taken from the text content of the option element! Some older browsers will always do this. This is why, as a rule I try and match my text string to the value, unless its multiple words, a non-unique value, or the value is in another non-friendly format, like an abstract number, id, or value a user will not recognize.<form>
), as the form really controls this setting over all its child fields. But often you will have a 'form' with default settings and want to override them in each form field. A difficult one to manage is "novalidate". In general, the code samples above showcase my "best practices" and recommendations for how each field should use this attributes.
<option>
and <optgroup>
elements for a list of recommended attributes (I have tried to include those in the 'select' code examples above).Below, I have added a very clean, widely supported piece of CSS code you can use to give your 'select' element a nice clean style that looks the same across many browsers and versions. This is the basic style I use for the 'select' example above:
select,
select:visited,
select:hover,
select:focus,
select:active {
display: inline-block;
width: auto;
height: auto;
min-width: 0;
max-width: none;
padding: .17em .17em;
padding: .17rem .17rem;
margin: 0;
text-transform: none;
border-radius: .2em;
border-radius: .2rem;
border: 2px solid #bbb;
background: #fff;
cursor: pointer;
-webkit-appearance: listbox;
-moz-appearance: listbox;
line-height: normal;
}
select:visited,
select:hover,
select:focus,
select:active {
background: #f9f9ff;
border: 2px solid #999;
}
select:focus {
background: #fff;
border: 2px solid #999;
}
This is some <small>small</small> text.
<p>Some text<spacer type="horizontal" size="20"></spacer>some text</p>
Some text
<p>Lorem ipsum dolor sit amet, mea enim erat id, regione iudicabit consetetur ius ex. Qui vide errem ut, ius id movet atomorum. <span style="color:blue;font-weight:bolder;">Sit pericula definiebas ei</span>, ex eam essent maluisset. <span style="color:red;font-weight:bolder;">Duis ceteros pro ut.</span> Mei eius labore ut. Iusto facete facilisi vel id, nonumy omnium constituto ad pro. Mei in sale option.</p>
Lorem ipsum dolor sit amet, mea enim erat id, regione iudicabit consetetur ius ex. Qui vide errem ut, ius id movet atomorum. Sit pericula definiebas ei, ex eam essent maluisset. Duis ceteros pro ut. Mei eius labore ut. Iusto facete facilisi vel id, nonumy omnium constituto ad pro. Mei in sale option.
<p>
element, the 'span' element wraps around smaller pieces of text within a larger paragraph, allow for styling or other CSS customizations of text. For this reason, it most often is used inside the 'p' element. Because the 'span' element has been around since the birth of HTML in the 1990's, this element has not changed in any of the browsers, and so is very reliable.also see <audio>, <picture>, and <video>
The 'source' element is only used as a child element for a 'audio', 'picture', or 'video parent elements in HTML5. It defines alternative "sources" of media for all three tags. Shown below is an example of how to use the 'source' element with the 'picture' element. In this example, the 'source' tags provide alternative images for the 'img' element.
<figure aria-labelledby="source1_caption" style="padding:.5rem;border:1px solid #bbb;background: #f0f0f0;width: auto;height: auto;display: inline-block;">
<picture id="source1">
<source srcset="image.webp" type="image/webp" />
<source srcset="weather.gif" media="(min-width: 800px)" type="image/gif" />
<img id="source1_img" style="width: auto;height: auto;max-width: 100%;" src="www.jpg" width="255" height="200" alt="image: World Wide Web" title="The World Wide Web" aria-label="Image of the World Wide Web" loading="lazy" onerror="this.onerror=null;" />
</picture>
<figcaption id="source1_caption" style="display:block;">
"Which Image Appears?"
</figcaption>
</figure>
* Note: My host provider does not support "WebP" images I found out, so if no "flowering tree" WebP image appears, it is not the code but my host provider. :(
<source>
tag attributes supported and their role in controlling alternative media:
<source />
. Do not let others convince you this is a "void" element or that this format is not compatible with HTML5, because it is.
This is some <strike>struck through</strike> text.
<s>
or "strikethrough" element which represents text whose meaning has changed, or the <del>
and <ins>
elements to indicate deleted text that has been replaced.
<p>This text has <strong>strong</strong> importance and should stand out.</p>
This text has strong importance and should stand out.
also see <link>
A 'style' element is a non-visual (invisible) element that resides inside the <head>
element of a typical web page. This element contains "embedded" style sheets that only apply to a single web page. Below I have listed a code example you can use to enhance your website with styles. Note: I do not recommend you use the 'style' element for styling websites, however, as it only applies to a single page and therefore wastes bandwidth delivering the same code over and over on every single page view. Instead, use the <link>
or "external" CSS style sheet strategy which applies a single downloaded style sheet to an unlimited number of web pages at once. It is also fully cached for weeks or months in the web browser. Note: The "strange" CDATA code that wraps around the CSS in 'style'. This is "extra" code designed to hide CSS styles in the tags from XHTML/XML parsers and older non-supporting CSS browsers (see my recommendations below for a full explanation). This code, however, works fine in all HTML5 browsers going forward.
<style type="text/css">
<!--/*--><![CDATA[/*><!--*/
p {
display: block;
clear: none;
padding: 0;
margin: 1em 0em;
}
/*]]>*/-->
</style>
<style>
) and "inline" element styles (<span style="color:blue;">my text</span>
) simply because external styles downloaded to the browser are cached for every page in your website and affect all web pages, not just one. Often inexperienced developers use inline or embedded styles and forget about externally linked CSS sheets. They assume they are slower, inferior, antiquated, or difficult to manage when the opposite is true. They then lose out on valuable, reliable, proven technology that is far superior to anything built today. Links to multiple external CSS files also download in parallel to each other in a very quick fashion in most browsers, so there are few delays. Browsers have been doing this for over 20 years. Unlike large libraries of scripts, linked CSS often has a very tiny footprint and so has very little affect on page rendering or paint delays, simply because modern browsers manage these downloads very effectively and have been for decades. Once your CSS files are downloaded, they are cached and indexed in browser folders, allowing future page views of your site to be rendered and painted in the browser very quickly. Note that these "embedded" styles are only really useful for "offline" styling of pages. The only real benefit to using these "embedded" style blocks was for caching of offline styles for devices like old handhelds, which reallu benefited from using cached pages with associated styles attached to them. Today, that is rarely needed.<link>
element recommendations for more details). If you leave off, say "media=screen", the styles will generally apply to "media=screen" by default in many older browsers using the HTML 4.1 spec. Note that this is the opposite for 'link' elements, which default to "media=all" today in HTML5. As with 'link', never use "all" explicitly due to lack of browsers support, but use "screen", "print", and specific types. For now, I recommend you do not use a media type setting on the 'style' element based on HTML5 recommendations. Instead, just leave it off and assume your styles affect all devices.<head>
of your web page. This forces the browser to parse and load the styles first into memory before downloading HTML content and should only contain styles that need to be fully preloaded first and which directly affect or control HTML right after before it is rendered and painted. This CDATA code below inside the 'style' element supports HTML5 parsing, XHTML, XHTML5, and very old browsers that do not support the style tag or even CSS. In all cases, using the code below will not blow up in any of the browsers or allow your styles to get rendered accidentally as markup or even text:
<style type="text/css">
<!--/*--><![CDATA[/*><!--*/
/* put your styles here */
/*]]>*/-->
</style>
Some History on this Strange Code Above: Going back to the 1990's, you were allowed to place these HTML comments "<!--" and "-->" inside the 'script' element to hide CSS and style code text from non-CSS supporting browsers, which would recognize the HTML comments and hide the style text. Supporting CSS browsers back then would ignore them and execute the styles. Why? These 'script' and 'style' elements read anything inside the tags as character data or CDATA, which means no HTML is recognized inside the tags. HTML comments are still HTML so ignored by them. So, most browsers that supported CSS back then ignored these HTML comments, as anything in these elements was considered CDATA, allowing CSS to execute safely for them. By the way, these now defunct older non-CSS supporting browsers included IE 1-2 and Netscape 1-3. For them, the HTML comments meant the style code was safely commented out. Added to this problem has been XHTML and XML parsers, which do not know the code between these tags is just CDATA. Such parsers would blow up if they parsed CSS that contained any XML entities or markers. Many of these XML-friendly parsers did not need CSS at all. To fix the code for them, I had to expand the comments above to force those parsers to ignore the CSS code, as well. And so that is how I came to develop the solution above. In the HTML5 browser world today, nearly all browsers known now support CSS. But adding the comments and safety code above allows you to still support a range of very old non-CSS supporting browsers, XHTML, and XML parsers combined, should you need to share your code or web pages with any of these parsers or browsers. They will not blow up now when encountering your CSS code using the comments above. The code above is completely safe to use now in newer, more modern HTML5 browsers. But when used, it will make sure your JavaScript blocks are ignored in XML parsers and non-CSS supporting older browsers alike.<style>
) and "external" (<link>
) style sheets in the <head>
of your web page affect the cascade order of similar style rules on elements? It is an important question. It turns out it DOES in modern HTML5 browsers, but did NOT in many older browsers (pre-2010)! Why? Older browsers used to have a very good rule the W3C used to require they follow. It basically said that no matter where external <link>
styles appear in the <head>
of your web page, "embedded" or <style>
CSS was always last in the order set inside the browsers cascade memory, not in your web page. In other words, embedded styles always cascaded over linked styles using the same selectors, even if you placed external linked CSS AFTER embedded CSS in your web pages. Linked external CSS elements always came before embedded CSS in the memory of the browser, no matter what physical order your code used. This is NOT the case in newer HTML5 browsers, I found out. This might be a subtle issue to you, but if you stack lots of "element" style rules in your external and internal style sections of your web page 'head' element, rules that use the exact same selectors, if you do not order your linked external CSS elements correctly then you might see some cascade over others, unexpectedly in newer HTML5 browsers! Order of styles now matters in your pages, where in the past it did not. The reason newer HTML5 browsers now strictly honor specific style sheet "source order" in the "head" of your page, regardless of linked vs embedded types, is because HTML5 has gotten lazier and looser in defining such things. In other words, be careful in the order you place linked and embedded styles, as they do matter today. Embedded sheets no longer have higher source order over linked sheets, as they did in the past. To match old and new browsers so they both work the same using external and embedded sheets, ALWAYS add your linked sheets (<link>
) above your embedded ones (<style>
) in the head of your page.
<!--[if IE 8 ]>
<link media="screen" rel="stylesheet" type="text/css" href="/styles/ie8only.css" />
<![endif]-->
<!--[if IE 9 ]>
<link media="screen" rel="stylesheet" type="text/css" href="/styles/ie9only.css" />
<![endif]-->
<p>Here is a chemical formula: H<sub>2</sub>O.
<br />Here is a famous equation: e=mc<sup>2</sup>.</p>
Here is a chemical formula: H2O.
Here is a famous equation: e=mc2.
also see <details>
The "summary" text is show below. It is the top gray "click-able" section in the 'details' element below.
<details id="summaryexample1">
<summary style="background-color: #ccccccff;box-shadow: 2px 2px 3px #aaa;">© Copyright 2022</summary>
<div style="margin: 0;padding: .2em 1em;background-color: #efefef;box-shadow: 2px 2px 3px #aaa;">
<p>Owned by Company ABC. All Rights Reserved.</p>
<p>All content and graphics on this web site are the property of Company ABC.</p>
</div>
</details>
Owned by Company ABC. All Rights Reserved.
All content and graphics on this web site are the property of Company ABC.
<details>
element for more detailed information about this element and all its features and properties.also see <canvas>
Below, is a simple example of how to use SVG in HTML5 to create an image dynamically in the browser. If your browser supports HTML5, then it will likely see the words "SVG" drawn in the middle. There are many more powerful examples of SVG art online.
<svg height="120" width="120" xmlns="http://www.w3.org/2000/svg" title="My SVG Image" aria-label="SVG Image">
<text x="0" y="0" style="font-size:3em;fill:green;">
<tspan x="32" y="55">SVG</tspan>
</text>
Sorry, your browser does not support Scalable Vector Graphics technology (SVG).
</svg>
If you plan to use "external" SVG XML files (which I recommend you do), you have the power to deliver alternative SVG images to regular HTML5 browsers with added bitmap versions or alternative images of your SVG in pixel formats for older browsers that do not support HTML5. Below is an example of a "fallback" code you can copy and modify as needed when supporting older browsers that do not support SVG. Modern HTML5 browsers will read the 'object', 'embed' or "xlink" image source, while older browsers will either see a pixel JPEG image or text.
<object
id="mysvgobject1"
name="mysvgobject1"
data="mysvgfile.svg"
type="image/svg+xml"
title="My SVG Image"
aria-label="SVG Image"
title="My SVG Image" aria-label="SVG Image">
<embed
id="mysvgembed1"
src="mysvgfile.svg"
type="image/svg+xml"
title="My SVG Image"
aria-label="SVG Image"
title="My SVG Image" aria-label="SVG Image">
<img xlink:href="mysvgfile.svg" src="myfallback.jpg" title="My SVG Image" aria-label="SVG Image"> />
<noembed>
Sorry, your browser does not support Scalable Vector Graphics technology (SVG).
</noembed>
</embed>
</object>
<canvas>
, the 'svg' ("Scalable Vector Graphics" or SVG) element is a fully-featured linear 2-D design feature that gives you complete control over images using simple XML code. It is fully compatible with HTML5 and markup, as a result. Like 'canvas', the browser is used in creating the image and visuals. But 'canvas' relies on a "one time" rasterized image call using the graphic libraries in the device's operating system. As such, it will not re-render the image as the browsers viewport changes. 'svg' elements, however, will redraw images, as they rely on the browser's rendering abilities to draw vector shapes in the viewport. This gives 'svg' elements a very fast and powerful edge over all other pixel-based, static, or rasterized image systems online. However, photographic imagery is not suitable for 'scalable vector images. So 'svg' is generally not used for high definition imagery or manipulating pixels in photos. Understand it has its place in solving some image-rendering issues, but not all.
<object>
, <embed>
, <use>
, or <image>
tag. The advantage to this technique is you manage all your complex SVG code externally and in modules you can add as needed using a set of small XML files. It also allows you to use cross-browser support for non-supporting SVG browsers, with an alternative pixel-based image in the 'img' tag for browsers that do not support the SVG code (see my example above).<video>
elements in my article, "How to Create a Cross-Browser Video in HTML5". I have created a custom version of this in the code examples above. You must use an external SVG file for this to work properly. Basically, using the 'object', 'embed', and 'img' tags, browsers that fully support SVG will display the external SVG file downloaded into 'object'. Some browsers use the 'embed' element to run an SVG application in the browser. Finally, those browsers that need to download the SVG file as an image can use the 'img' tag. All legacy browsers would download a plain image you supply that is a screenshot of the SVG file. This would give you nearly 100% fallback support of your SVG image using alternative pixel-based images in older browsers.also see <col>
and <colgroup>
Included in this section is <table>
and all its child elements: <thead>
, <tbody>
, <tfoot>
, <tr>
, <th>
, <td>
Below, I am showing an example of a basic table template you can use in all your projects. This one has all the traditional "grouping" table elements, including 'thead' at the top and 'tfoot' at the bottom. 'thead' and 'tfoot' not only support the 'tbody' data in the page, but are added at the top and bottom of printed pages in many browsers. The 'tbody' contains all of the main content cells. Included are two examples of spanning, a process which allows cells to stretch across multiple rows and columns using the "rowspan" and "colspan" attributes. The new ARIA attributes of "aria-colcount=4" and "aria-rowcount=6" tell screen readers the expected count of columns and rows in your table, if you know those values. I've also added the "scope" attribute in the header elements to help screen readers understand labels as they relate to groups of columns. I have added an optional "headers" attribute to cells to help screen readers associate them with headers using their "id" values. If you use "scope", this is not needed. But I have added it to show how they are used. I have also added the optional 'colgroup' and col' elements to create the blue color. These two elements are generally non-traditional elements used to control background or other design features in tables. But I do not recommend you use 'colgroup' or 'col' elements in tables at this time. Try and use CSS "class" attributes with styles instead to control the look-and-feel of your table's columns and rows.
<table id="tableexample1" title="Table Example With Column Groups"
aria-label="Table Example 1" aria-colcount="4" aria-rowcount="6">
<caption>Table Example 1 : Column Groups</caption>
<colgroup>
<col style="background-color:white;"/>
<col span="2" style="background-color:lightblue;" />
</colgroup>
<thead>
<tr>
<th id="header1" scope="col">header 1</th>
<th id="header2" scope="colgroup" colspan="2">header 2</th>
<th id="header3" scope="col">header 4</th>
</tr>
</thead>
<tbody>
<tr>
<td headers="header1" >body 1</td>
<td headers="header2">body 2</td>
<td headers="header2">body 3</td>
<td headers="header3">body 4</td>
</tr>
<tr>
<td headers="header1">body 1</td>
<td headers="header2" colspan="2">"colspan" applied</td>
<td headers="header3">body 4</td>
</tr>
<tr>
<td headers="header1" rowspan="2">"rowspan" applied</td>
<td headers="header2">body 2</td>
<td headers="header2">body 3</td>
<td headers="header3">body 4</td>
</tr>
<tr>
<td headers="header1">body 2</td>
<td headers="header2">body 3</td>
<td headers="header3">body 4</td>
</tr>
</tbody>
<tfoot>
<tr>
<td headers="header1">footer 1</td>
<td headers="header2">footer 2</td>
<td headers="header2">footer 3</td>
<td headers="header3">footer 4</td>
</tr>
</tfoot>
</table>
header 1 | header 2 | header 4 | |
---|---|---|---|
body 1 | body 2 | body 3 | body 4 |
body 1 | "colspan" applied | body 4 | |
"rowspan" applied | body 2 | body 3 | body 4 |
body 2 | body 3 | body 4 | |
footer 1 | footer 2 | footer 3 | footer 4 |
Below, I am showing an example of a table with an added nested table so you can see how that is done.
<table id="tableexample2" title="Table Example Containing a Nested Table"
aria-label="Table Example 2" aria-colcount="3" aria-rowcount="3">
<caption>Table Example 2 : Nested Tables</caption>
<thead>
<tr>
<th scope="col">header 1</th>
<th scope="col">header 2</th>
<th scope="col">header 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>body 1</td>
<td>
body 2
<table id="tablenested1">
<tr>
<td>nested 1</td>
<td>nested 2</td>
<td>nested 3</td>
</tr>
</table>
</td>
<td>body 3</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>footer 1</td>
<td>footer 2</td>
<td>footer 3</td>
</tr>
</tfoot>
</table>
header 1 | header 2 | header 3 | |||
---|---|---|---|---|---|
body 1 |
body 2
|
body 3 | |||
footer 1 | footer 2 | footer 3 |
This example shows how you can have "headers" ('th') in columns, as well as rows. This example contains both types to show you how you can create tables with horizontal and vertical titles. Notice I changed the "scope" in the 'tbody' header cells to "row" to tell screen readers these left-hand headers represent the row of cells only. The 'tfoot' group was removed at the bottom of the table, as it is not needed.
<table id="tableexample3" title="Table Example Containing Multiple Headers"
aria-label="Table Example 3" aria-colcount="4" aria-rowcount="4">
<caption>Table Example 3 : Multiple Headers</caption>
<thead>
<tr>
<th scope="col"> </th>
<th scope="col">top header 1</th>
<th scope="col">top header 2</th>
<th scope="col">top header 3</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">left header 1</th>
<td>cell 1</td>
<td>cell 2</td>
<td>cell 3</td>
</tr>
<tr>
<th scope="row">left header 2</th>
<td>cell 1</td>
<td>cell 2</td>
<td>cell 3</td>
</tr>
<tr>
<th scope="row">left header 2</th>
<td>cell 1</td>
<td>cell 2</td>
<td>cell 3</td>
</tr>
</tbody>
</table>
top header 1 | top header 2 | top header 3 | |
---|---|---|---|
left header 1 | cell 1 | cell 2 | cell 3 |
left header 2 | cell 1 | cell 2 | cell 3 |
left header 2 | cell 1 | cell 2 | cell 3 |
Recommended Attributes
Recommended Attributes
Recommended Attributes
Recommended Attributes
Additional Table Elements
Table Elements I Would Avoid
body table {
display: table;
margin: 0;
padding: 0;
border: 1px solid #000;
border-spacing: 0;
border-collapse: collapse;
vertical-align: top;
}
body thead {
display: table-header-group;
margin: 0;
padding: 0;
border: none;
border-spacing: 0;
border-collapse: collapse;
}
body tbody {
display: table-row-group;
margin: 0;
padding: 0;
border: none;
border-spacing: 0;
border-collapse: collapse;
}
body tfoot {
display: table-footer-group;
margin: 0;
padding: 0;
border: none;
border-spacing: 0;
border-collapse: collapse;
}
body tr {
display: table-row;
margin: 0;
padding: 0;
border: none;
border-spacing: 0;
border-collapse: collapse;
}
body th {
display: table-cell;
margin: 0;
padding: .5em;
padding: .5rem;
border: 1px solid #000;
border-spacing: 0;
border-collapse: collapse;
text-align: center;
font-weight: bold;
color: inherit;
}
body td {
display: table-cell;
margin: 0;
padding: .5em;
padding: .5rem;
border: 1px solid #000;
border-spacing: 0;
border-collapse: collapse;
color: inherit;
}
This 'template' element and its content below would be hidden by most HTML-supporting browsers until revealed by some type of JavaScript code.
<template id="template1">
<p>My hidden Template Text.</p>
</template>
see <form> for more details using <textarea> in forms
Shown below is a complete code sample of the <textarea> element, which you can copy-and-paste into your web project. It has a rich set of attributes I recommend you use for each scenario. The visual design for this form is shown below the code. With these examples you have a complete set of code you can use in your web forms.
<form id="formtextarea" name="formtextarea" method="post" action="#" title="Textarea Example" aria-label="Textarea Example" autocomplete="off" autocapitalize="off" spellcheck="false">
<fieldset id="formtextarea_fieldset1" name="formtextarea_fieldset1" form="formtextarea" style="background-color:#fff;">
<legend style="background-color:#aaa;color:#fff;">Textarea</legend>
<div>
<label for="formtextarea_textarea1" title="Textarea">Textarea Label:</label><br />
<textarea id="formtextarea_textarea1" name="formtextarea_textarea1" title="Textarea" aria-label="Textarea" tabindex="0" contenteditable="true" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="true" maxlength="200">Enter your text here...</textarea>
</div>
</fieldset>
</form>
<form>
: Element Around Your 'textarea' Elements: When you wrap a form tag around a 'textarea' control, it tells the browser your 'textarea' is associated with a specific form "id" value and will only submit the field elements associated with that control. If you have multiple textareas and form fields to submit to a web page, it is crucial you know what select belongs with which form. You can still place the element outside a form if you give it a 'form={yourformid}' attribute with a value associated with a specific form "id". In that case, it will be submitted with all the fields inside that specific form. However, I do not recommend you move form controls outside of a form, as some older browsers may fail to send the right data when submitted.<label>
Element with Your 'textarea' Element: Try and use the 'label' element before your 'textarea' tag, then add the "for" attribute with a value that matches the textarea's 'id' value to associate the two together. This links the label to the form field and allows the browser, search engines, and screen readers to connect the two, adding semantic meaning. Often, the browsers will float the label text above the textarea control. But I have added a break after it as textarea boxes tend to float right as an inline-block element (see my code samples above for examples of labels and textarea controls). "clicking" on the label's text auto-selects the textarea and places your cursor in its box. Also add a 'title' attribute with description of your textarea to the your label.<form>
), as the form really controls this setting over all its child fields. But often you will have a 'form' with default settings and want to override them in each form field. A difficult one to manage is "novalidate". In general, the code samples above showcase my "best practices" and recommendations for how each field should use this attributes.
Below, I have added a very clean, widely supported piece of CSS code you can use to give your 'textarea' element a nice clean style that looks the same across many browsers and versions. This is the basic style I use for the 'textarea' example above:
textarea,
textarea:visited,
textarea:hover,
textarea:focus,
textarea:active {
display: inline-block;
width: auto;
height: auto;
min-width: 20em;
min-width: 20rem;
max-width: 100%;
min-height: 10em;
min-height: 10rem;
padding: .2em;
padding: .2rem;
margin: 0;
-webkit-appearance: textarea;
-moz-appearance: textfield-multiline;
cursor: text;
overflow: auto;
resize: both;
background-color: #eee;
word-wrap: normal;
border: 2px solid #bbb;
border-radius: .2em;
border-radius: .2rem;
line-height: normal;
}
textarea:visited,
textarea:hover,
textarea:focus,
textarea:active {
background: #f9f9ff;
border: 2px solid #999;
}
textarea:focus {
background: #fff;
border: 2px solid #999;
}
<tt>This is teletype text. If your browser supports it, it should be in a monospace font.</tt>
<span>
inline element with a CSS "class" attribute added and the following style declaration: "font-family:monospace". So, avoid use of the 'tt' element.
<p>It is <time datetime="2021-06-26T22:00:00Z" title="2021-06-26T22:00:00Z">5 o'clock</time> here in my state. But what time is it in your state? My 'time' element might help!</p>
It is here in my state. But what time is it in your state? My 'time' element might help!
see <html>
<html>
element for a full description.Avoid the 'track' element' in video in HTML5 until wider support for common track file "types" are more widely supported. But, an example of how to use the 'track' element in 'video' elements is shown below.
<video id="trackvideo1" controls="controls" preload="metadata" title="My Video with Tracking">
<source src="video1.mov" type="video/quicktime" />
<source src="video1.ogv" type="video/ogg" />
<track default="default" kind="subtitles" srclang="en" src="video/track.vtt" />
<p><strong>Sorry, this video file will not play. Your browser does not support the video element or the file formats available.</strong></p>
</video>
<video>
and <audio>
elements, and allows you to load caption timed text using a secondary "track" text file and display that text within the parent media file. This element is supported in HTML5, but because of the industry-wide failure to agree to a standard (to match common media types with tracking file types in web display), most text tracks technology will fail to achieve cross-browser minimum support, so I do not recommend its use today.<video>
section. But here is a bit more.
see <li>
<li>
element for a full description.Note that this element used to be called the "underline" element, but is now called the "Unarticulated Annotation", indicating text that is a non-textual annotation. This means it should be used to decorate text that needs further explanation, like a spelling error.
This is some <u>mis-pelled</u> text that is given focus.
u {
/* Older IE browsers only */
text-decoration: underline dashed red;
/* Try and use the "spellcheck" wavy error line instead. */
text-decoration: underline wavy red;
}
<p>The formula is: <var>a</var> + <var>b</var> = <var>c</var>.</p>
The formula is: a + b = c.
<code>
, <kbd>
, and <samp>
in that 'var' formats text to represent abstract computer programs, keys, equations, or ideas.
<figure aria-labelledby="myvideo" style="padding: .5rem;border: 1px solid #bbb;background: #f0f0f0;width: auto;height: auto;display: inline-block;">
<video id="video1" alt="video: Fireplace Video" width="320" height="240" style="width: 320px;height:240px;border:1px solid #bbb;" controls="controls" preload="metadata" title="A Video of a Cracklin' Fireplace" aria-label="Fireplace Video">
<source src="video1.mov" type="video/quicktime" />
<source src="video1.ogv" type="video/ogg" />
<p><strong>Sorry, this video file will not play. Your browser does not support the video element or the file formats available.</strong></p>
</video>
<figcaption id="myvideo" style="font-size:smaller;">"Fireplace Video" [<a href="http://creativecommons.org/licenses/by-sa/3.0" target="_blank" rel="noreferrer nofollow noopener">CC BY-SA 3.0</a>],
via <a href="https://commons.wikimedia.org/wiki/" target="_blank" rel="noreferrer nofollow noopener">Wikimedia Commons</a></figcaption>
</figure>
Notes on this Video Example: If your browser supports the video element below you should see a movie of a fireplace. In this example, I have given HTML5 browsers two video "sources" to choose from: MOV (Apple Quicktime) and OGG. Your browser must support the new HTML5 'video' element and one of the two video codecs in order to see the movie.
<source>
child element with its "type" attribute to support your many video encoded alternatives (as show in the code above).<picture>
element with multiple fallback child <source>
tags representing alternative video file sources inside it. The browser will pick the first source file format it can play successfully from a list, or report a text message indicating no file format or audio element support.
<div style="border:1px solid black;width:auto;padding:.5em 1em;">
<p>This (wbr) <wbr /> sentence can (wbr) <wbr /> drop down only where (wbr) <wbr /> I put a wbr element.</p>
</div>
This (wbr)
<br />
element, the 'wbr' does not create a "break" in the word or sentence unless it finds an opportunity to do so. It is rarely used, however.<wbr>
element version. But, as I mention elsewhere in this tutorial, never use incompatible XML elements like this as they will cause your markup to fail in XML or XHTML parsers should your pages be parsed that way. Instead, always use the correct "XML-friendly" version: <wbr />
Xml Data Islands provided a way to store data in specialized xml tags. These would not be rendered in certain browsers (mainly Internet Explorer pre-version 9) and allow you to use various API's to extract client-side data. The two main methods used were to code directly into 'xml' tags or overload the script tag with these elements. Note: This latter idea was likely to fail in XHTML browsers without special CDATA tags. Today these tags are no longer needed because scripting API's and alternative data access via scripts has changed how and where client-side data is stored.
<xml id="xmlid1">
<xmldata>
<data>text data</<data>
</xmldata>
</xml>
<script id="xmlid2" language="xml">
<xmldata>
<data>text data</data>
</xmldata>
</script>
<xmp>Non-formatted text with <span style="color:red;">HTML</span> text.</xmp>
Non-formatted and escaped <span style="color:red;">HTML</span> text.
<div itemscope="itemscope" itemtype="http://schema.org/Movie">
The itemtype attribute above has been assigned to a third party "schema", and uses its content definition for "Movie" to help identify available properties for the data shown below.
<h1 itemprop="name">Avatar</h1>
<p>Here the search engine will see an item for a movie schema with one property assigned called "name" whose value is "Avatar". What is contained in the itemscope is itemprop or a property of the "Movie" schema type. This then tells search engine exactly what the content is and its category of data used by its property and value.</p>
</div>
This isn't a required HTML attribute, but can be helpful in building apps that will be indexed by search engines. Google is already using this to improve search results and add more granular metadata meaning in all parts of the web they index. Because most HTML is self-describing, this is often extra fluff to what is built into HTML already, and so not needed. Like the "data-" attribute or 'data' element above, it does not affect form field data sent to the server, the design of web pages, or the semantic characteristics of HTML. It is not helpful in terms of adding real meaning to your web pages. It is mainly for JavaScript or certain search engine effects. I would only use it for enhancing search-engine friendly markers in your HTML and for pages that have lots of tabular data. One example is large public-facing, informational websites that will get heavily indexed or archived by many types of parsers, bots, and search engines. Microdata is only fully supported in Firefox on Android at this time, so without wider browser adoption I cannot recommend Microdata.
<dev class="h-card">
<span class="p-name">Your Name</span>
<a class="u-email" href="mailto:name@website.com">name@website.com</a>
<a class="u-url" rel="me" href="https://twitter.com/sometwitter">@sometwitter</a>
</dev>
Many of these new technologies are being integrated into public-facing websites build by 3rd party products like Wordpress and others. They then allow a limited set of browsers and parsers a slightly improved connection to your page data. This data is then parsed into data formats like JSON or XML, and linked back to your site. However, until we see wider adoption and more more general use, none of these technologies add a real benefit to your pages. Unlike Microdata, Microformats seems to have wider support in browsers. But Microformats is still is not supported by Internet Explorer or Safari browsers, desktop and mobile. It still does not yet replace standard search engine parsing or indexing to a degree that a solid argument can be made for its consistent use in building HTML pages. Until we see wider adoption and IDE's enable more implementations of Microformats in JSON, I do not recommend a major effort in using this new technology. Unless you are designing a very large public-facing site with with data tied into authors, organizations, social media, and indexed data, I see no reason to use Microformats at this time.
<h3 property="http://purl.org/dc/terms/title">Some Title</h3>
<span property="http://purl.org/dc/terms/created">2021-12-20</span>
Hypertext Markup Language (HTML) is the language of the World Wide Web. HTML has been around since 1990 and was invented by a British computer scientist named Sir Tim Berners-Lee. In fact, you can still view his first HTML website online! The general HTML markup language has not changed much since 1990. I have been coding in it since 1998, and since those early days have fallen in love with its simple, reliable, easy-to-use language (as have millions). Of all the dozen or more advanced languages and frameworks I have used over the years as a software engineer, HTML is still my favorite!
Here in 2022, HTML5 is the newest markup language for creating web pages on the Internet. It has been around since 2008, but was not widely adopted until after 2010. HTML5 is based on HTML4, and has enriched the older standard with new elements and features. Since its conception, however, HTML5 has moved in a slightly different direction from what I call the "original HTML". HTML5 has in fact become a looser form of the earlier HTML markup languages. For starters, it is no longer aligned with SGML (the language for defining standard markup languages). Nor does HTML5 follow standardized markup rules as it did in the past two decades since its invention. After 2010, the organizations that now manage HTML5 have decided to abandon stricter standards and move forward with what I call a "vendor-based model" for how HTML should be interpreted. That has meant increased flexibility under its new "Living Standard" for browser makers. But the price paid, in my opinion, has been a disconnect from "good" coding practices of the past by many new web developers using new HTML5.
It is true that HTML5 no longer has any connection to its older and more mature cousins: HTML4, XHTML, and XML. HTML5 now accepts a wide range of coding conventions, mistakes, errors, sub-standards, and styles. The browsers and parsers today that implement it have followed that "free-form" idea and are all stuck in an unending state of partially implementing the latest flavor of HTML5. It is a very forgiving language. But as a result, HTML5 is no longer well-formed, will not validate, nor does it follow older, standardized markup rules. The doctype declaration for HTML5, for example, no longer even needs a true "Document Type Definition" (DTD). Even the "quirksmode" concept of modern browsers flipping from "standards mode" to a quirks rendering mode is quite vague. This means the HTML5 coding "standard" is really a stripped down version of what HTML4 and XHTML1.0 transitional used to be. And that is why in HTML5 we have returned to "tag soup".
But in its defense, modern HTML5 has been designed in such a way to allow a more "open" interpretation, and to allow a wider range of old and new conventions to be adopted and accepted across many devices, browsers, industries, and users. Many say that kind of flexibility is a good idea. But long term, I disagree. Forgiving coding standards without any enforced rules just allow bad or lazy coding practices to creep in. Already some new developers online are now advocating for a very proprietary, older, subversive "standard" of HTML markup that returns the language back to a non-standard, older, sloppier markup format most of us last used (and abandoned) in 1998 with HTML 4.1. The web will now be an even bigger patchwork quilt of broken HTML if we all allow it to go backwards and support poor markup conventions. All this may bode well for a more "adaptive", forgiving, human-centric web. It means struggles later for the machine-driven AI, "no code", or automated web of the future.
But there is hope! For starters, you do not have to use HTML5 the way it was "recommended", or even use HTML5 at all! There is now a "polyglot" form of HTML5 called XHTML5 that follows stricter coding strategies, but which supports nearly all HTML5 elements. You can still use old XHTML transitional, XHTML strict, and even old HTML4, if you like. Coding in the XML-compliant versions do require well-formed markup, which also means they automatically work in sloppier HTML5, should you switch. The problem is that the reverse is not always true. Many of these antiquated coding "recommendations" used by HTML5 may support a greater variety of markup practices used online, but they would never support any of the more robust and reliable XML practices used in these other formats.
The fact remains that HTML5 is what is hip, cool, and popular at the moment. And so that is what we should all adopt for building web applications on the World Wide Web. But, just because HTML5 has consistency flaws does not mean your HTML5 code has to follow bad coding practices. HTML5 is very forgiving, right? That means web developers and designers can adopt HTML5 as their primary web coding language but still follow "good" markup practices, if they like. HTML5 markup can follow "well-formed" XML markup practices and cleaner XML conventions, for example. It just isn't required to. But why would you do that when you can use ugly, sloppy HTML and get away with your "tag soup"? The answer is simple:
By following the stricter XML markup standards in your HTML code, your HTML5 web pages can now be backward and forward compatible with XHTML5, XHTML1.1, XML, and even old HTML 3.2 or HTML 4.1. It can be nearly 100% cross-browser compatible with all these old and evolving newer standards all at once!
There will always be markup in your HTML that is not 100% compatible with every language standard. But you can get close if not all the way there if you follow a few simple rules. That is at the heart of what "HTML5 Best Practices" means. But achieving that means hard work, erasing your bad assumptions, then re-learning all over again the RIGHT ways to build web sites in HTML. There are other reasons for you to follow more standardized XML-based markup rules in your HTML. The main one is so you deliver to modern browsers a fast and easily parsed HTML for the DOM tree (Document Object Model) that rendering and layout engines in browsers will inevitably build and display millions of times. Knowing that, why deliver sloppy markup to all those visitors? With cleaner code, rendering engines can build "Render Trees" faster in the DOM, generate faster layouts, and paint the viewport quicker, more reliably, and more efficiently using XML-based, standardized HTML. The user's browsers just run better! In addition, your ECMAScript "flavor-of-the-month" API can also parse, deliver, and read your HTML better with fewer errors or hiccups if the markup is clean, well decorated with attributes, consistent, and follows solid XML conventions. Some applications now read, write, and dynamically parse HTML pages as XML data, or even store them as XML in a database then recreate HTML from this data. Generating sloppy HTML from data that was not compatible with XML in the first place and that had to be "interpreted" or stripped of errors first, would make no sense, right? Why not build clean HTML from good HTML and return better HTML?
I am not talking about perfection here, or even trying to validate your HTML in some way here. But the evidence is clear. Why not start off learning how to code HTML5 the RIGHT WAY using XML-compatible conventions? That is one of the MAIN REASONS for this tutorial....to teach you the right way to code. If the markup is clean and well-formed, as all XML is, then you will have zero issues with any of the things listed above, and your HTML will work well in XML or XHTML, or in future browsers using future HTML standards should you have to convert it. But coding in good, future-proof HTML means going BACK to older HTML conventions for answers, and forgetting current usage trends and ideas written about online today. Much of the articles written today about web technologies like HTML simply reinvent a wheel that was never broken!
So, to start coding in good, clean, standardized HTML that is XML-compliant, simply follow my "Rules for Well-Formed HTML5" below. It will get you 99% of the way there!
<input />
<Input /> or <INPUT />
<img id="myimage1" class="myclass" src="myimage.jpg" alt="My Image" />
<Img Id="MyImage1" class="MyClass" SRC="MYIMAGE.jpg" Alt="MY IMAGE" />
<a id="myanchorid2" class="myclass" href="http://mywebsite.com/mypath/" />
<a id="2myanchorid" class="my-class" href="http://mywebsite.com/my path/" />
<a href="http://..." onclick="MyMethod('my string');" />
<input checked="checked" />
<input checked />
<img />
<img> or <img/> or <img></img>
<br />
form of the "break" element. This ending "/" with preceding space makes it backwards compatible with HTML4, HTML5, XHTML, XHTML5, XHTML1.1 strict, and is 100% XML-compatible and HTML5-compatible, as well:
<br />
<br>, <br/>, or <br></br>
<p><span></span></p>
<p><span></p></span>
<a href="https://mitchellstokely.com/" id="myanchor1" title="This is a Link to my Web Page in a New Tab" rel="noreferrer nofollow noopener" tabindex="0" target="_blank" aria-label="Internal Page Link">My Web Page</a>
<a href="#">My Web Page</a>
"Absolute URLs are more reliable than relative URLs because they don't break if file locations change; for instance, if "/events.html" moves to "/events/ index.html", the absolute reference to "/content/logo.gif" will still work. Also, absolute URLs help avoid a CSS bug in some old browsers that misunderstand relative file references in style sheets."
Below is a complete HTML5 template you can use that has all the recommended elements and attributes needed to build a good web page. This is a great starter template that you can cut-and-paste into any HTML5 web project knowing it will always work well in many browsers, old and new. This one has many good features for full cross-browser support in numerous browser versions and types, including full support for the latest and greatest HTML features used in more modern HTML5 browsers. (The elements shown are all discussed in detail in my HTML5 element section above.) This code below is well-formatted and coded in lower case text, is XHTML5/XHTML/XML friendly, includes all code needed to support CSS and JavaScript, and even has alerts for those browsers that do not support styles and scripting. What is best about this template is it required no JavaScript to create any of these features! It is pure HTML! You will need to add custom HTML page elements to this template under 'body', add custom server paths and files, add your external style sheets, and any JavaScript code or file paths needed. You will need to apply custom CSS to this template. It includes many hidden "gems" you will see in the code below that you will want to hide, show, or customize using CSS.
If you want my HTML5 template with my new HTML flexible layout and cross-browser "grid" code built in (see "Final Cross-Browser Layout Grid Example"), I have added the integrated code for all that below. It includes the HTML5 template, layout, and complete grid system. It also includes a semantic-friendly "menu" in the header you can use. Just cut-and-paste the code below into a blank HTML page and you have it all! Just be sure to customize and style it as you like. This code is also mobile-friendly ad will collapse for smaller device screens. Note: The CSS for the "grid" and "menu" is inside embedded style blocks in the code below, which you can move into your style sheet, if you like.
The huge advantage to using this code block below, is it not only gives you a powerful, pre-built HTML5 web page, but it comes with a complete, expanding web page layout using the new CSS "grid" property, that supports not just desktop browsers, but compacts its layout for mobile ones, as well. You can easily customize it as you like. It also includes HTML5 and partial CSS grid support for older browsers, like old Internet Explorer, with alert messaging and stacked layouts if they fail to understand the new CSS3 "grid" property. Using the code base below will give you a powerful head start in building a solid, cutting edge HTML5 page that works well in newer browsers, but which has basic support for many older ones, as well.
Now you can get the CSS Cascading Style Sheet system behind this web page! Download my Universal CSS Framework at GitHub!
Already in 2022, I am seeing web developers embrace Angular and React CSS designs, which by default inject horrible "embedded" CSS style sheet blocks into the head of every web page they compile. This means they download, compile, then spit out into the browser's DOM and memory non-cached style sheets into every page (and on every new visit to the domain) when they could have used a single linked style sheet that is cached and used for styling thousands of web pages and views.
I wanted to show you what embedded CSS looks like below so you can avoid it. Some young developers incorrectly call "embedded" CSS an "inline" style sheet when its correct name is an "internal" style sheet. I sometimes drop internal CSS into a page like this when I'm building styles that will be moved to linked sheets later. It is a temporary home for my styles. In this web page I have added a few internal styles that only this page will ever see or use. That is a case where its ok to be lazy as I have demonstrations here where I have to add CSS I demo. But on large web project, after I'm done, I will erase these embedded style blocks completely from the 'head' of my page and add them to my linked style sheet. Its very easy to maintain all your CSS via linked files this way. The advantages are huge!
"Linked" Style Sheets are Superior! A linked CSS file will be downloaded and cached one time and for days or weeks by the user's browser, saving the server and the user extra calls to the server as well as reprocessing time. Linked CSS files are associated with one website's domain and/or subdomain by the browser, so caching and use of its style sheet applies to every page a user visits under that URL. The styles persist in styling layouts and text no matter where a user goes in the site or what pages they view. As the user surfs the site it will use the cached style sheet stored in the browser's file cache, pulling it from its store on the user's computer as needed and storing it in memory. The browser then paints the render tree using the cached CSS file when laying out the various websites HTML pages and structures.
"Embedded" or "Internal" styles are always downloaded per page and are gone when the user leaves the site (unless the page itself is cached). That means they have to be reloaded with each page view in the website. In a traditional web site, embedded CSS is often downloaded over and over again with every call to the server for each page this way, so it is quite wasteful. Often sites repeat the same styles between pages so total bandwidth used is very bandwidth heavy using these embedded style solutions. Linked style sheets saves your site huge bandwidth costs, not to mention savings in time-to-deliver, since pulling a linked sheet from the server, one time, then from a user's cache every other time is much faster than pulling a web page with embedded CSS over the wire from the server each time. Linked sheets won't be reloaded on each visit or page view if caching is enabled, where web pages which change with content will force the styles attached to be reloaded using embedded styles. Linked styles can also apply to thousands of web pages, where embedded CSS applies to one.
In Google's Angular API, that model is not always used the same way. But components and modules in these JavaScripted API's that store embedded CSS must compile and then repeat the same CSS in various modules that could have been shared via one master sheet. In Angular's case, a download of the same JavaScript modules would also contain the same CSS, forcing a fresh download of those styles every refresh or visit of the browser to the domain. It is simply a CPU and memory hog downloading, storing, and displaying page-level CSS this way! Caching CSS via a link is just so much more efficient.
<link media="screen" rel="stylesheet" type="text/css" href="styles.css" />
Below is what NOT to do. Angular and many JavaScript API's apply embedded styles below to their dynamically-created HTML pages. Never use embedded CSS blocks like this unless you are ok customizing CSS on a page-by-page basis.
Every web page needs an "h1" heading at the very top of the page. It defines the purpose and content of the page to search engines and screen readers. It has powerful influence over how pages are indexed by search engines. It can be placed either above the navigation in the 'header' element or inside the 'main' or 'section' elements as a page title. The 'h1' element should be your choice, as it represents the top level heading element, with smaller headings and content after it.
Because many modern web pages do not always use heading elements in their navigation due to design issues (enlarged title text) you should use CSS to change its placement and design. One strategy is to make your 'h1' title text your header's default home link. Some designer's wrap the header logo inside the "h1" element. But the 'h1' text should be specific to your page's content. So, my recommendation is to place this link inside the main page area inside 'main' or 'section' elements.
Search and the H1 Element: If you really want your HTML to tell Google or other search engines what your web page content is about, you want to match the meta tag 'title' text with your 'h1' text title text so they are in sync. Search engines love this! As a matter of fact, search engines are designed to read either your meta tag 'title' or your 'h1' when determining a search entry for your page. So count on your 'h1' text showing up in search engines! It is one more reason to make sure you use the 'h1' reliably.
ARIA Accessibility: In the example below, I have also added ARIA accessibility features that further connects the heading with the HTML semantic layout structure. The "aria-labelledby=mainheading" attribute below connects a page's 'section' element and document with the 'h1' heading element, allowing screen readers to associate the web page document features with its top-level title. This is an ARIA accessibility feature and helps screen readers know what the section does as defined by the header element. As above, linking the 'title', the 'h1' heading, and accessibility labels aligns your pages meaning and purpose with viewers, search engines, and screen readers all at once!
Headings are used by search engines to identify content and to decide important content sections in pages. Use headings to help users and search engines determine "document structure and content" of a page and its subject. Search engines will read the text in a heading and give it importance if not use it for search titles in cases where the meta tag title is absent or not sufficient. Below are the 6 heading title tags and the relative spacing you can expect when using them. In general us "h1" for the top of your page and lower numbered headings for subtitles. I have put background colors on these only so you can see the line spacing used for headings. Remember, use headings ("h1" primarily) with rich keywords that match both your meta tag "title" and "description" tags, as well as the keyword-rich text content of your web page. This affects positive search engine rankings in all your pages, when done correctly.
Note: In ARIA you do not need to add the role of "heading" (which identifies a subsection heading of the page) as screen readers know what the "h" elements represent. Because the "h1" heading element identifies the tag as a heading element, these types of ARIA roles are really not needed. I would only use the 'role' attribute if you used a non-standard element for a text heading. (see my HTML5 element list on "h1" headings for more details.
HTML uses elements like "b" (bold) and "i" (italic) for formatting text. Formatting elements were designed to display special types of text visually. But some say its now better to use 'strong' rather than "b", and 'em' rather than "i". Leaving these elements unformatted and changing them with CSS is also fine. But by using 'strong' and 'em', you are letting the user's browser or user settings determine format while identifying important semantic content to search engines and screen readers. Search engines will give emphasis to tags like "strong" and "em" as they imply something beyond visual formatting as those elements add special importance to plain text. Note: Using CSS, I like to format "strong text" exactly as "bold text" using 'font-weight'. But I apply "font-weight:bolder" so that strong text is relative to what formatting exists, bolder not just bold.
Bold text - Bold with no importanceUse 'blockquote' for larger quote "blocks" without the curly quotation marks, and 'q' for inline, shorter quotes with the curly quotation marks added. I generally believe this set of tags is typically not needed unless you are doing formal article writing, news stories, or where you are taking information from a source that is not your own. Most young people I have noticed use quotations excessively online when paraphrasing is just as acceptable.
Use the "q" tag for short quoted text (Note that browsers insert curly quotations around quoted text here):
My old teacher used to tell me, Build a future where people live in harmony with nature.
For longer quotes use "blockquote". (Note these are not quoted with curly quotes but indented). Like with the <ins> element, the 'cite' attribute is needed if your content comes from another online source. This prevents accusations of plagiarism!
The World Wildlife Fund has said the following:
For 50 years, WWF has been protecting the future of nature. The world's leading conservation organization, WWF works in 100 countries and is supported by 1.2 million members in the United States and close to 5 million globally.
"Horizontal rules" are an old HTML trick that is still useful in all modern browsers. Use horizontal rules for separating content. It is just that simple! The original horizontal rule originally was created as a way to replicate the small separations found inside an article or inside a book novel's chapter where the scene often breaks away to a different one and a marker or rule is added to tell the reader of the sudden change. The same can apply to web pages. But the horizontal rule concept has gradually expanded from simple literary concerns to separation between lots of different types of content online. Notice the space plus forward slash in the 'hr' element below. I highly recommend you use this XML-compatible version. It is not required but backwards compatible with XHTML, as well. As noted in all my HTML5 designs, the rule is also friendly with search engines who also will identify a separation of content and ideas when it finds a horizontal rule.
Content here...
Different content follows a horizontal rule...
With HTML5 now, you can turn many elements and images into click-able buttons. We will not cover that concept here as in nearly all cases, using HTML5's native, semantically friendly 'button' and 'input' elements should cover all your button needs. Keep that fact in mind if you start to get creative and try and define your own buttons in HTML. Now let us proceed...
There are two main types of buttons in HTML. Most web developers forget this fact. There is the 'button' element and the 'input' element. I have styled the two types the same inside my custom "reset" style sheet so they look the same.
<button id="buttonexample1" name="buttonexample1" type="submit" aria-label="Submit" title="My Cool Button" tabindex="0">My Button</button>
<input id="inputbuttonexample1" name="inputbuttonexample1" type="submit" value="My Button" aria-label="Submit" title="My Other Cool Button" tabindex="0" />
The 'button' element is always a "button". The 'input' element is the second type of "button" and can be a button or a non-button. It is a web form control but has many other sub-types besides the "button type". Both elements use a 'type' attribute to define what type of button they are. But the 'button' element is ALWAYS a button regardless of its type. Confused yet? It gets better.
Both 'button' and 'input' elements share the same button 'type' attribute and can have one of these three types: 'button', 'submit', and 'reset'. Without the 'type' attribute, the 'button' element is a "submit" button by default, while the 'input' element is a 'text' input control by default (non-button). The 'submit' type is the ONLY type that will post all form field input data to the server. More on that later. The plain "button" or "reset" types do not. The plain "button" type never does anything and requires JavaScript or other scripting to respond to any user clicks or events. Besides its three button types, 'input' element can have a fourth button type called 'image' which allows it to use an image as a button. The "image" input button type performs like a "submit" button. More on that later. The only real difference between the 'button' and 'input' elements as buttons is the fact the 'button' element allows HTML elements between its tags, while the 'input' does not. And so the 'button' element allows a richer set of design possibilities, where the 'input' element only allows text on its button using the 'value' attribute, or with an image using the "image type". This means 'button' elements can be styled to look visually more appealing as HTML can be added between the start and end button tag set. The two types of buttons possible are shown below using the 'button' and 'input' elements with their various 'types'. Example:
'button' elements can have rich HTML for its button text and design...
<button aria-label="Submit">Some <strong style="color:blue;">HTML</strong> here...</button>
...while 'input' does not and is stuck with its 'value' attribute text...
<input type="button" aria-label="Submit" value="My Button Text" />
The "Image" Button: As mentioned, the "image" button type for 'input' elements does allow you to use an image for a button, but a background image in CSS could also be applied. Remember image 'input' buttons are also submit buttons. Because both 'button' and 'input' controls can have images in some form they essentially work the same:
<input type="image" aria-label="Submit" src="css/default/content/import_excel_button.gif" alt="Image Button" title="I am an Image Button!" tabindex="0" aria-label="Button" />
However, you can now create buttons from ANY element! Using CSS and the ability to create images or anchor elements or even divs as buttons now, there is no longer a preference in terms of which element to use when creating buttons. But it is still best semantically to use the 'button' or 'input' elements for all your buttons. There are some minor visual layout and value submission bugs in old IE6 and IE8 browsers using the 'button' element. But today in modern browsers, those issues no longer exist. Most developers still prefer using the 'input' with "submit" type to post form input data to the server. The 'input' is also a member of a larger family of matching form controls, so fits better as a button with most traditional form control designs.
BUTTON STYLES: Keep in mind you can style these as you like with beveled or raised surfaces, colors, images, etc. Here we are just focused on their elements as markup and the semantic meaning their button-nature implies, not the myriad of CSS designs possible. The 'button' element's default UA designs by default traditionally had a raised or beveled look in many older browsers with a gray background to help identify it as a true button element apart from a generic input control. In fact all buttons are NOT part of HTML itself but considered "replacement" elements or "objects" controlled by the operating system. That is why Macintosh browser buttons always look so different from Windows ones, or phone buttons, etc. I like the old gray Windows looking buttons from long ago. Some newer browsers still style it that way, but others replaced it with a more modern look. Again, the operating system has a big influence. Bootstrap and other style sheet systems have flattened some default button designs through their "reboot" sheets. I generally do not like those styles. Note: In CSS, often adding a "border" CSS style to a button will trigger the button to abandon the raised button-like default OS styling and flatten the button to look more like HTML elements. Weird, huh?
HTML5 STYLING: In addition, be aware that HTML5 now allows you to apply more CSS pseudo-classes to buttons. They also trigger in most modern browsers new events you can capture and control, like colored "outlines" on rollover or other custom features like different "states" of 'inputs' and 'button' elements. These include special events like when a button is hovered, focused, valid, invalid, active, or disabled. The best design choices for these two elements is to simply place simple formatted text, border, rounded corners, and raised effects to them as needed and utilize the more widely supported pseudo-classes in CSS to style their backgrounds, outlines, or raised effects (I have a fully styled example below in the "form" HTML5 example).
BUTTON ATTRIBUTES: There is a rich set of attributes on buttons, which I have outlined in the "HTML5 Element List" above. But here are a few "gotchas" and "best practices" on attributes. If you leave off the 'type' attribute on the 'button' element, the 'button' without a 'type' attribute defaults to the "submit" type. That means when clicked, they will post all form data in the page to the server by default. So keep that in mind. The other button 'types' for both 'input' and 'button', "button" and "reset", do NOT submit data to the server, as mentioned above. "Reset" clears all user form control values from all forms in a given parent 'form' element. The "button" type does nothing until you assign some type of scripting or event response to their click events. "submit" is the dominant type for 'input' and 'button' "buttons" and so you will use it in nearly all your HTML5 pages to submit data to the server. The other "gotcha" is when you have multiple forms of inputs in a single page. Be sure you add the "form" attribute with the name of the form the submit type button will post to the server. In addition, all submit buttons and their parent forms by default submit forms as a "GET" rather than a "POST". This means, when pressed, if you have not set the "formmethod=post" attribute on the 'form' element (recommended) or the 'button'/'input' then all form name-values pairs from the input controls are sent via the url as query strings rather the host header which is slightly more secure. I will cover more of this info in the "HTML5 Element List" above.
New Forms of HTML5 Buttons: With the advent of newer JavaScript API's, WebAPI and REST events in web projects, and JavaScripted SAP's (single-page-applications), many buttons are now created using anchor elements and onclick events the web designer controls and captures. The form data is then dynamically processed in the browser or client and sent to the server using XMLHTTPRequest objects in JavaScript, rather than trusting the natural server POST capabilities of the native "submit button" itself. In addition, in HTML5 you can turn any element like images or links into buttons. Many element can now have a 'type' value of 'button" or 'submit', as well, which behave like a submit button. Adding JavaScripted event capture to your pages and these new non-button elements means you as designer now have more control over how and where buttons in the web page submit data. But these are all "illusions" of the original, native browser button itself. Even though I too have built these JavaScript systems and enjoy the freedom to do so, I still recommend you use the 'input' or 'button' for all your button events for semantic reasons and as a fallback in case scripts are disabled or you need to support user-agents that do not support click events on non-traditional button elements. The 'input' and 'button' controls still tell users and browsers what elements control submission events. Helping developers and browsers understand which elements are real "buttons", rather than assigning obscure HTML elements as buttons, has larger impacts on how semantically-friendly web pages perform with screen readers and the blind, as well. Therefore, I recommend you stay with the more traditional elements when creating buttons and reconsider using these JavaScript API's in the future, as they distort the original purpose of the web browser submit button and will never be as semantically relevant and as important to the Web as plain HTML5 elements.
* For more detail on button attributes and features see the "HTML5 Element List" or my HTML5 form example.
"line-height" in CSS style sheets has often messed with HTML layouts. Most young web developers fail to understand line-heights and how they affect HTML layouts. So, I thought I would cover those briefly below.
Let's cut to chase on line-heights. Most text in HTML is displayed as a font-family and font-size, then given a "default" line height that most often matches its font and font-size. These three items give text its essential display in the space of the typical HTML web page. Without them it would not appear at all. In the example below, I have added simple text to a 'div' element. All I have added to the 'div' is a border. The font-family, font-size, and line-height are using the browser's default values. Notice that the font floats inside the box but has a strange but natural border at the top and bottom. This is created by the "line-height". I have set my web page's line-height to "1.5" for better reading. You can see that extra spacing below. That has created the small extra space above and below the text in the bordered 'div' box below. I went ahead and added it to the style of the element, as well, so you can verify it works.
<div style="margin:0;padding:0;border:1px solid #000;line-height:1.5;">Line-Height Test</div>
Below, I've gone ahead and changed the above example. I have turned the font-size into pixels and the line-height explicitly assigned in pixels, so we can start to test a few things below. "font-size:16px" is the same as the default font-size in most browsers for most fonts set at the default medium size.
"line-height" can be either a number or a unit, like "px" mentioned above. There is a big different between the two, however. When using the numeric version, line-height is inherited first from a parent element, then calculated based on the element's own font-size, which could also be inherited. That is the opposite of line-height in say "em", "%", or "px" where line-height is first calculated from the parent, then applied to the child.
When "line-height" is defined as a number, "1" is the same value in pixels as the font in pixel size. So "font-size:16px" when assigned as line-height of "1" has a "line-height:16px". You can also use "em" but I do not recommend "em" for line-height as its corresponding font-size is always relative to the parent's value which can compound when inherited by child elements.
You may ask, what is the DEFAULT line-height, if not "1"? Strangely enough, the default "line-height" value is NOT "1" but varies by font family, size, height, and browsers. Using the keyword "normal" returns the line-height to its default or natural value. Some estimate the default or "normal" is around a numerical value of "1.14", which is more of an average of most font line-heights. It often varies, because some fonts come with elaborate glyphs or accents that stretch far above the capital letters. This default value is only applied when you use "line-height:normal". As a general rule "normal" is good when you want to reset back to the font's natural "line-height", though no one can tell you what that translates to in pixels or numerical values! I believe using "1" is still safe for controlling stricter compressed line-heights on most fonts, though in some cases that value for line-height causes some minor bleed over of text in their containers. Most designers now apply larger line-heights than "1", like 1.2, 1.5, etc for readability anyway, which exceeds the natural line-heights. They are safe to use this way when larger. However, as we will see, larger and larger line-heights still push text blocks outside many container blocks!
Below, I have now added a "16px" line-height (same as "1") to this new example, which overwrites my web page's larger "1.5" value. You can see how that's collapsed the white space around the text now, yet keeps some spacing for text accents on capital letters. For some browsers, the bottom text might still break out of the parent container by a pixel or two using "line-height:1". If this is an issue, use "normal" again.
<div style="font-size:16px;margin:0;padding:0;border:1px solid #000;line-height:16px;">Line-Height Test</div>
The spacing in "line-height" actually is pretty strange. It acts like a "box" around the text, creating space much like a block-level element, starting from the middle of the text, expanding above and below it. But it also acts like a "float" in CSS in that it can break out of any parent block that holds it. We will see that next. Below is an example of a new text block using the same 'div' text as above but with a few changes to the line-height. Here, I have set "line-height" to "0". I have also set the parent to "height:16px", the same as the line-height, and added a gray background so you can see how a font's line-height affects the text as it gets smaller or larger than the parent's height.
Notice that the text below at "line-height:0" has moved up into the box and now sits halfway above the gray box's top boundary. With "line-height:0" the text moves up to the top edge of the 'div', yet oddly sits partially above it. It appears that as the line-height collapses to zero, that the text moves up in its parent container until its middle-axis sits just below the top of its container. This shows that the text exists independent of the container block, and that the text's anchor or reference point in space begins at the mid-point of its text height. Therefore, line-height creates "space" for the text to exist in the parent box but creating space above and below the middle axis of the text block. It does not, however, control the appearance of the text by hiding it when "0", as you might expect. It simply expands space around the text so the text can float inside block-level elements. The text still doesn't break out of the container, however. But its "line-height" does control how and where it positions itself inside its parent container.
<div style="height:16px;background:gray;font-size:16px;line-height:0;margin:0;padding:0;border:none;">Line-Height Zero Test</div>
Let's now expand on what we just showed. "line-height" now is easy to understand. It appears to simply create space around text starting with its middle-axis, going above and below that point, so text is placed or "floats" inside this imaginary box. Because line-height space exists simply for the text space and is independent of parent block space, it can hold itself in block-level parent elements or break out of it like a float. You can see that effect below. I have added various increases in line-heights to the example below. Notice as the line-height increases the text moves back into the parent box, then breaks out again and pushes below it. Knowing how line-height works, you can now understand its "weirdness" when text breaks out of your carefully designed boxes.
Below is the code:
The above examples occur because we have set the "height" on the 'div' to a set pixel value, along with line-height settings smaller or larger than the space needed to fill the 'div' parent's 16px height. This is one more reason to NEVER USE PIXELS IN WEB PAGE LAYOUTS when defining web pages as ANY change to font-sizes or line-heights could cause text to break out of pixel-based web designs. Now, an easy fix to the above "weirdness" is to first of all, set all parent containers of text to "height:auto", or set height to elements to "em" units which will scale as the text scales in size. Fonts start out with the same size as the user's default font-size, using "em". This allows line-height to increase and stay inside the 'div' parent container, in most cases. The important thing to realize here is that "line-height" acts very much like a block-level element, creates space for text to exist, and can break out of block-level elements. Now that you know these facts, you can safely define line-heights in your pages and fully understand the consequences if you increase or decrease their values in parent blocks. Below is an example of a good line-height design where I have simply set "height:auto" so the height always expands as line-height expands and "line-height:normal", which matches ideal font line-height to whatever font-family and font-size is assigned to the text. Using "auto" and "normal" means our text will NEVER break out of a container and always use the preferred dimensions as set by the end-user. I also like to use "font-size:medium" in all my web pages, which tells the page to always start with the user's preferred or default medium font size (whatever size they chose becomes the "medium". Using "line-height:normal" with this user-centric "font-size:meaning" CSS property, means your web pages are not only 100% scalable by font and line-height, but they zoom as the user chooses while "honoring" the user's chosen font settings in the browser.
<div style="height:auto;background:#ddd;font-size:16px;line-height:normal;margin:0;padding:0;border:none;">Normal Line-Height Text</div>
Use the 'pre' element for preformatted text and to preserve whitespace and display text EXACTLY as it is entered or formatted. Note: This is NOT the same as the 'code' element, however, which is designed to display and semantically mark text as computer code. 'pre' elements can be quite useful, however, when combined with code, as they convey the idea of code, but also code that is carefully formatted like all code usually is. For that reason many websites will wrap a 'pre' around a 'code' element, or set a 'textarea' block to a 'pre' CSS style to simulate a block of carefully formatted, monospace styled, coding text.
Use the 'pre' tag to preserve whitespace, font type, and font size formatting:
My Bonnie lies over the ocean. My Bonnie lies over the sea. My Bonnie lies over the ocean. Oh, bring back my Bonnie to me.
Use the 'pre' tag with 'code' element together to show off cool computer code exactly as it is typed! Note: I had to "escape" the greater than and less than HTML code below for this to work.
<select name="cars">
<option value="volvo">Volvo</option>
<option value="fiat">Fiat</option>
<option value="audi">Audi</option>
</select>
As a side trick, I like to use the <textarea> element to hold code samples instead, as shown above, as I don't have to escape any HTML I drop into it. ( I am using this trick in this web page!). This one uses a plain unstyled 'textarea' tag set, but you can add more font styling to it, as needed. Copy the code below to recreate the textarea "code box" shown above:
<textarea spellcheck="false">
<select name="cars">
<option value="volvo">Volvo</option>
<option value="fiat">Fiat</option>
<option value="audi">Audi</option>
</select>
</textarea>
Most new web developers forget to add important 'title' or "tooltip" attributes to their click-able or important elements. The 'title' attribute acts like a mouse rollover and should be added to every link, image, or multimedia element you create to tell search engines, users, and special parsers what the element does. I even include them on form fields and inputs and buttons in my HTML. Often images are ok with just the 'alt' attribute. But I often add a descriptive value to 'title' attributes on images so users know what the image is about in case 'alt' is not shown. Links need 'title' values as well, so users know where the link goes before it is clicked. I often tell users on rollover where the link goes. You can even add 'title' to special Angular elements that have complex interactive features so on mouseover users know what the feature does and how to interact with it. The 'title' attribute then allows all your page elements to passively help users identify what that element does before it is clicked. 'title' is easily the most underrated HTML feature ever invented!
You can see the "tabindex=0" attribute added to this html element below. "tabindex=0" assigned to an element adds it to the global index list created by the browser. You can also set specific tabindex values and create your own custom tab order. This is frequently done in form inputs a user fills out in a specific order. Setting "tabindex=1" would start a user at a specific control and works like 'autofocus'. It controls where users go to in a page initially. "tabindex=-1" removes an element from the tabindex set by the browser and is great for removing items from a strict list of form fields that you want a user to follow, while skipping over ones you do not. I add "tabindex=-1" to 'disabled' and 'readonly' input form field types, links, as well as 'reset' or other buttons I don't want data entry people to ever tab onto. Add the "autofocus=autofocus" attribute to immediately take them to a specific item regardless of tabindex. When added you will be taken to the input below immediately and see the blinking cursor in the input below.
We use "tabindex" numbers to control how users move through large complex forms when hitting the tab key or completing forms. But without these a user will usually follow an order the browser assigns by default. Often, however, without tabindex the browser will tab through other fields, like images that may or may not be interactive. Tabindex allows you to control what is part of that browser tab index. Without 'tabindex' or 'autofocus' you would have to set tabindex on every form item for it to focus on the first one. So use 'autofocus' to start a user on a specific button or field, then add and 'tabindex=0' to all the form fields users can tab naturally through using the tab order set by the browser.
For complex forms add specific tabindex numerical values to control how they move through your fields. Note that 'autofocus' does shift the user to a specific item in Firefox, Chrome, IE, and Safari, but might not work in older browsers. Important: When using tabindex for input fields it is always best to wrap input fields in a form tag below. This is good practice as you can have multiple form elements per page in all versions of HTML where the tab index might shift. Note: IE 10 and older do not support tabindex values, nor does Opera 10 or older. In old HTML4, the tabindex attribute was only relevant for elements that could receive focus, including 'a', 'button', 'input', 'object', 'select', and 'textarea'. In HTML5, tabindex is available to any element that can receive focus. That is one more reason to consider applying 'tabindex' numeric values explicitly on form fields and buttons rather than trusting the browser to decide using "tabindex=0".
Below is the code:
Code inside 'style' and 'script' elements has special meaning in HTML and HTML5. Anything added inside those tags is interpreted as "character data", or in XML-language, "CDATA". This means, unlike normal elements, text inside those elements is never parsed as markup. If it did, it could break your website. You could accidentally type something with an ampersand or a left or right bracket as used in HTML tags and it would break!
Often HTML5 developers don't care if their websites support XML or XHTML. It should work only in HTML5. But there are those of us that love the fact our websites get "as close as possible" to XML and XHTML. Why? Because it means your site is easily copied into many technologies and is easily parsed into XML if you needed that ability. In some cases, XML-friendly markup is parsed faster and more JavaScript-friendly, as well. Some say, well, HTML is "tag soup" anyway, so who cares. Others have shown how ending tags, as XML generates, creates special issues in HTML. I am of the opinion that XML-friendly is always the way to go in your HTML markup design, regardless of those special cases.
To address these issues in our special 'style' and 'script' elements, you need to realize XML and XHTML browser parsers will NOT see the content in those elements as CDATA by default. You must add CDATA rules to your HTML to make them XML-friendly. Otherwise, anything that contains special HTML markup characters will fail. If you copied your 'style' or 'script' elements into an XHTML page as is, the XML parser would try and interpret your CSS and JavaScript as markup and blow up without the extra CDATA section added. HTML5 already reads the content inside 'style' and 'script' tags as CDATA (character data). You only need to add the CDATA block if you want your HTML5 page to be compatible with XHTML and XML. Otherwise, they read the 'style' and 'script' tag content as markup. Because XML and XHTML parsers reads everything inside elements as potentially more markup, adding CDATA prevents certain characters from being interpreted as XML or other types of character references.
XML and valid XHTML (application/xhtml+xml) will read the 'style' and 'script' element content as PCDATA, meaning the contents are parsed as markup and potentially break with special characters. The purpose of adding extra CDATA sections isn't to fix anything in HTML but make your pages cross-compatible with XML-related parsers and agents. If you add these new CDATA markers into these tags for XML support, most major HTML5 browsers will fail when they parse those tags as they are already using CDATA rules behind the scenes. So added CDATA blocks have to be commented out for those agents with special "hacks".
So how do you combine all that so your HTML5 is XML-friendly in 'style' and 'script' elements? And should you care?
In the early days of HTML, we used to use some very simple techniques in our 'style' and 'script' elements hide code from browsers that did not understand CSS and/or JavaScript. Going back to the 1990's, CSS always allowed you to place HTML comments after the <style>
element to hide CSS text from non-CSS browsers (IE 1-2 and Netscape 1-3). So we simply hid code from them using plain HTML comments, like so. Supporting CSS browsers would ignore the comments as these tags read them as CDATA, or plain character text, not HTML, while non-supporting browsers read everything inside them as normal HTML, so understood the HTML comments:
<style type="text/css">
<!--
body {background: green;}
-->
</style>
JavaScript had the same problem. Many browsers, like IE 1-3.01 and Netscape 1-1.4, did not fully support JavaScript (or JScript), so we had to hide scripts for those browsers as well using HTML comments, like so:
<script type="text/javascript">
<!--
alert('hello world');
//-->
</script>
When XHTML1.0 and XML parsing came on the scene after 2001, however, we had a new problem. Because JavaScript could contain some XML reserved characters, like & or < or >, any scripts containing that code would create a validation error in XML parsers, like XHTML. The reason was the same as described above for CSS: These browsers did not consider code inside 'style' and 'script' tags as CDATA, or character data. That means those offending characters were read as HTML, so would blow up in XHTML. To fix this issue in JavaScript, we simply added a CDATA section inside the comments to make sure XHTML could interpret the scripts as JavaScript, just not read the reserved XML characters as HTML:
<script type="text/javascript">
//<!--[CDATA[
alert('hello world');
//]]-->
</script>
You would think this final code fix would solve all our problems. But it has not. It works well in most browsers, but some HTML5 and XHTML5 browsers could misinterpret this code, as could a mix of older browsers and XML parsers with various levels of support for scripts and styles in various combinations. In some cases you needed to hide the code completely from XML parsers, and in others you needed to hide CDATA markers which are redundant in modern browsers who already interpret the tags as CDATA.
So, what is the best solution today, to address all these problems? I am a purest here and like my HTML5 content to still be XML/XHTML-friendly, regardless of what markup recommendation I am using. I also like my pages to work in browsers that know CSS and older browsers that do not. So I have added two solutions below to support all those scenarios and which will display your styles and scripts in modern browsers without errors. My solution below is something you can safely paste into your 'style' and 'script' tags and keep using CSS and JavaScript exactly as you have before knowing its completely XML-friendly!
`My solution below will do the following:
Notes on Code Below: In HTML5, html comment markers ("<!--" and "-->") are treated like CDATA by default inside style and script elements, so are completely ignored (comment tags do nothing in 'style' and 'script' elements). After ignoring comments and applying CSS and JavaScript comments, the top and bottom lines in the code blocks below are hidden in newer browsers and do not interfere with your CSS or JavaScript code. Some older browsers do not understand CSS or JavaScript code, but do recognize html comment markers. And so, these old browsers comment out all the CSS and JavaScript within the 'style' and 'script' elements below if they fail to know CSS comments (/**/) or JavaScript comments (//). The html commented code blocks are removed and the "<![CDATA[/*>" remains as an empty unknown element to them (unrecognized elements in HTML are always ignored). Finally, XHTML and XML parsers also recognize the html comment markers correctly, but also know the CSS and JavaScript comment codes. The final parsed block wraps a CDATA rule set ("<![CDATA[...]]>") around all styles and script code, applying any CSS or JavaScript comments as normal, then running the remaining uncommented styles or scripts inside the CDATA block as usual.
Simply paste the two code blocks below into your web page and replace the 'style' and 'script' elements you currently use. This code solution thus solves all three scenarios and will make your HTML page one step closer to being 100% XML-friendly!
With JavaScript now dominating the browser world, you may find yourself capturing 'anchor' links or the button's "submit" events in JavaScript, then ignoring the hyperlink or button's URL to the Internet. This is often used to allow user's to press a button or link and have JavaScript process the event or do something with the data before sending it to the server. Maybe you want to record a user clicking a link before you send them away from your website to an outside URL. Maybe you want the "submit" button and the form field data to be parsed, validated, then sent to a REST service using Javascript instead of posting via the browser to the server directly?
Often this "hijacking" of the form submission by JavaScript is semantically a bad design idea. But you can allow this as long as you account for people that have JavaScript disabled. Those people should be allowed to at least post to the server or come back to the same page or another page with a message if the event fails for them. So, how do you support your JavaScript methods and event capture, but stop users from linking off in the first place. How do you do that but support non-scripting browsers?
There are actually several tricks you can use to accomplish this strange feat!
In the case of anchor elements, using "return false;" inside your "onclick" event on the 'a' element allows you to keep the anchor 'href' URL in cases where you want a safe "fallback" hyperlink for browsers that have JavaScript disabled or where scripts are not supported in the user agent (1-5% of user's now). You can use the anchor "#" sign as the value for the 'href' URL, an empty string, or a special URL for the href should your script fail. Note that you must use an 'href' attribute in all cases so screen readers know it is a hyperlink. Removing the 'href' attribute is another option, many say. But removing the 'href' attribute on an 'a' element removes the ability of the element to perform as a hyperlink. So that option is moot here. Without an 'href' on an anchor means the anchor is no longer a hyperlink and just an HTML tag with a click event on it that is captured. Bad idea!
Below are three examples that will work to allow JavaScript to capture the click event and perform some action, followed by "return false;", which disables the ability of the link to function. JavaScript controls that click event now. If a browser did not support scripting, or a screen reader or other agent for the blind was used, then the script might be disabled but the anchor's 'href' URL still function anyway without destroying the user's experience. In this case, an empty ("") or anchor ("#") would route the user back to the same page. In the case of a special URL added (as I have done below) a hyperlink to process data or explain an error with a message is possible now, should the script fail. In all three versions below, the JavaScript alert box is allowed to fire, then "return false;" disables the hyperlink. But should scripting be disabled, the 'href' hyperlinks below would all fire ok and take the user somewhere by default. This is a nice fallback design that is cross-browser friendly!
Notice clicking any of the links below pulls up the JavaScript alert box but does not go anywhere after that.
Below is a popular trick used to disable hypertext links using a script. This trick only works when JavaScript is enabled in the browser. A script called "javascript:void(0)" is now added inside the href attribute below. This new script is ignored as a URL address but disables the hypertext link from working. This trick works because JavaScript has hijacked processing of the "href" URL value while returning an empty value. "javascript:" is a pseudo URL command and tells the browser to intercept all code processed after the colon and process it as script rather than as a URL string. This allows you to run various kinds of scripts when a link is clicked rather than routing off to a URL. As you may or may not know, JavaScript functions always return a value. If they have no value they return 'undefined'. "void()" does the same thing but forces an empty script response back to the browser when the link is clicked by the user. So using "void()" allows you to run a script that does nothing, stops all return values from any JavaScript run in the attribute, and disables all page navigation using the link. This makes this trick different from the empty URL's above that still allow the browser to process the href attribute and whatever URL resource that does or does not appear there.
Note: All these tricks can be applied to 'button' and 'input' "submit" type buttons, as well. These tricks do not just disable submission of form data but allow you a safer fallback pattern for older Javascript-disabled browsers to use when scripts do not work and the click events need to be processed naturally by the browser.
"Hiding" things in HTML and CSS confuses most developers. There are really three different ways to "hide" or "remove" items in web pages: Remove their "visibility", remove the item visually and physically from the page, and lastly, you can move something off the screen entirely.
Before talk about hiding things, let us talk briefly about the browser's Document Object Model. When your server sends elements to the browser, its parser and render engine build a tree of elements in memory and then paints them to the browser's web page viewport from its DOM or "Document Object Model" tree. Any element you remove entirely from the HTML you send to the browser is obviously not part of that DOM tree. That is usually the best way to hide anything, right?
Generally, when a developer says they want to "hide" something they are saying that they do want the HTML elements they sent to the browser to be displayed there and take up space, but just not be visible...temporarily. But that crosses into a gray area. Often, when you hide something, it is part of the DOM tree, just not visible on the screen. In that situation the item takes up space, but is invisible. But there are other times where you want the item to be both invisible and also not exist at all in the page...to not be part of the DOM tree of the browser, temporarily. Lastly, there are times you want the item to be visible and part of the page's tree and structure, just not be available to be seen and accessed on the page by a certain type of user or browser. Let's look at example of how to handle all these different scenarios.
Below is an example of how to visibly hide something that is still part of the DOM and inside the viewport, normally, and which still takes up space. Often a developer wants to use the item in scripts or to take up space but just wants to hide its visual aspects only. We use 'visibility:hidden' in CSS to do that. Note: We avoided using this element years ago as many older browsers didn't fully support it. It was not supported till IE4. But IE 4-7 still have issues with 'visibility' inheritance such that their child elements are often still shown when you apply "visibility:hidden" to a parent container. However, in modern browsers and IE8+ you will not have those issues, so 'visibility' today is a viable solution. Note that "visibility" is an inherited property unlike "display", so its children can override the parent's setting.
Using the "visibility:hidden" style on the box below, its inner text exists in the page and the DOM, but is visually hidden. Notice that the outlined box still reserves space for the hidden text, though it is hidden visually. Use this technique to maintain space for the item, but just hide it visually. Also note, if children of the element still wanted to be seen they could override the parent's "hidden" value and still be seen.
Below is an example of how to both hide something visually but also physically (though often temporarily). This technique removes an item from the painted DOM view completely, so it is hidden visually and physically just like it never existed. Keep in mind when you do this, the item's space in the page is also removed. Use this if you temporarily want to remove an item from the page's DOM tree, completely. We use 'display:none' in CSS to do that. Note: "display:none" is by far the most popular way to "hide" HTML elements and blocks of content. "display:none" has the widest support in even the oldest of browsers going back to Internet Explorer 4! But beware of one bug I found. IE (all versions 1-6) and old Mozilla browsers would download all "hidden images" inside blocks with "display:none" hidden. The correct standard is NOT to download hidden material on these hidden blocks until display changes to any other non-hidden type. Netscape 4 series also did not support "display:none", so we had to use "visibility: hidden" or "visibility: false". So, plan on this weird prospect in some browsers. But otherwise, display:none" takes its block of content, and all its children, out of the DOM. What most developers do not known is it also hides the item by removing it from the painted DOM tree of the web page so it no longer takes up space, as well. It removes it completely from the page. However, the item still exists in the pages unpainted tree, so most scripts can and do still access these types of "removed" items to "unhide" them by setting them to "display:block" or "display:inline" as a toggled item. So, they do exist in the DOM, just not the visual tree format created from it. Note that "display" is not an inherited property unlike "visibility", so its children cannot override the parent's setting.
WARNING! One of the very scary aspects of the use of "display:none" in form field elements (like 'input') is the fact that any form field with "display:none" is NOT sent to the server when the form is submitted! Keep this in mind when using "display:none" as it is a way of also blocking elements from being sent or parsed by the browser that might normally appear in POST data or read by outside 3rd party applications. That is one reason why "disabled" or "readonly" form field attributes were invented. So keep that in mind. You can control what fields are seen and POSTED better through attributes than showing and removing blocks of content with CSS.
Using the "display:none" style below, this text and its space no longer exists in the page but is removed completely. Notice the block holding the text is completely collapsed like it never exists. The item has been temporarily removed from the painted DOM tree.
Finally, below is an example of how to hide something completely from view for all browsers and users, but not affect its visibility or placement in the actual web page or structure of the DOM. This technique simply hides specific elements or blocks of content by moving them far offscreen. We have used this trick to keep an object that a screen reader with no CSS support would need to display at the top of a page for accessibility reasons, but for general public viewing should never see. We often want certain non-visual HTML elements to remain as part of our pages and the DOM, but not take up real state in the page. We often have content we want hidden to suddenly appear for certain types of people. Screen readers used by the blind is one such example. But how do you do that?
"position:absolute" does just that by moving a block of content out of the "page flow" and offscreen. In the example below the 'template' element is not a feature that should ever appear as a visual element in the page, yet should remain a functional element holding content, if needed. So I often move such elements way offscreen to hide them completely from the user. But I don't want such elements stripped out of the page completely by "display:none". Hiding it through CSS 'visibility' would really not make sense either as its not a visible element in HTML5 browsers, anyway. But older browser could try and fill the page display with its content as they don't know what this new HTML5 <template>
element is. So this is a perfect candidate for hiding something through "positioning". Other examples of when to use this technique are accessibility features like "Skip To Content" links at the top of a page you want the blind whose browsers don't read CSS to access but not your other users to ever see in your pages.
New in HTML5: Finally, something different! I have not used this technique much due to limited IE support. But you can now use the "hidden" HTML5 attribute to hide most elements in your web page now. Adding "hidden" as an attribute to an element means the tag and its content is part of the DOM and source, but is visually hidden from the viewer. It works just like CSS "display:none". Notice I added the XML-compatible version of 'hidden' with a value, as in "hidden='hidden'". "Hidden" appears to have wide support in many browsers today in 2022, including IE11 and Edge browsers. But beware, Internet Explorer 10 and earlier do NOT support the 'hidden' attribute., which might cause problems when hiding critical things they must not ever see. That is why I prefer the CSS options above using "visibility:hidden" and "display:none", which have much wider support in all older and newer browsers alike.
Using the "hidden" attribute below performs just like "display:none". Notice the box has collapsed when the item is hidden.
hidden text
This is one of the "additive" features I enjoy about HTML5, as it simply adds value to your HTML without punishing older browsers who do not have this feature. You can now use the "spellcheck" HTML5 attribute to tell the browser to enable its native spellcheck feature (if one exists) for an element. Adding "spellcheck='true'" as an attribute to an element means the tag and its content is checked for spelling. "Spellcheck" appears to have wide support in many browsers, including IE11 and Edge browsers. However, older browsers would not recognize it. That is why I would use it as an add-on, not as a required feature. If you end up needing mandatory spell checking for input, then consider a JavaScripted solution instead.
Try typing several words in the input box below. Misspell something in the text and see if your browser supports spell checking. A wavey line should appear under a word which you can right-click to choose an alternate word option from a popup list. This is not generated by a script, add-on, or even HTML. Your browser should come with this feature enabled, naturally. Note: It is rare to use the "spellcheck" attribute on 'input' elements. It is more common to add this attribute on 'textarea'. But I have added the feature below for demonstration purposes only.
Every developer should know how and why margins magically merge between certain elements in HTML. It is not intuitive but important you know how and why margins collapse. The "collapsing margin" has been around since the birth of CSS in the mid-1990's. Its interpretation by browsers has been spotty, however, confusing what should have been a consistent implementation. But the rules for how neighboring margins are merged has always been a confusing topic, even for me. I am still discovering weird things in browsers today that are not consistent. That is why its always helpful to review some basic ideas about margins, as the way they merge and collapse is important in HTML.
In HTML in the so-called "CSS Box Model", a margin is an invisible boundary you can add to any element so that a space is created between them. This has four directions, top, right, bottom, and left. In CSS you can use the "margin" property to represent the four margin areas: "margin-top", "margin-right", "margin-bottom", and "margin-left", or a shorthand version simply called "margin". (You can Google the types of units and spaces you can create using "margin"). But when combining vertical stacks of elements with margins, in CSS2 they are designed to collapse or "merge" into one unified new margin. Why would they do this?
The reason is simple: In the early days of the Web, the "web page" was mostly designed to support documents and text displays patterned after published books and journals such that text spacing was simulated in HTML and CSS designs. To do that, combining two blocks of text having upper and lower padding needed to be reduced to match the same spacing of text as paragraphs in books. To do this, "margin collapsing" was invented in CSS.
In HTML and CSS, the top and bottom margins of blocks are often combined into a single margin whose size is the largest of their individual margins (or just one of them, if they are equal). This is the basis for the behavior known as "margin collapsing". So the bottom of one paragraph text margin or block would be combined with the top of another, the large height winning and used as the default margin between them. The largest margin essentially pulls the smaller margin up into it so it is ignored. This is the basis for how top and bottom margins now combine in HTML and CSS today. Margin collapsing does this combining and collapsing mechanism to prevent repetition. This might seem counter intuitive but its design allows styling of numerous blocks of content without double-spacing between them, instead using single spacing to match how book text might perform naturally in the publishing world.
Important: Padding and borders on block elements do not collapse ever or follow these rules! They are always honored and NOT combined, as they are always a part of the blocks's total dimensions.
It turns out margin collapsing rules go a bit deeper than the main rule mentioned above. So, I'm am listing the rules on margin collapsing in HTML below:
Let's now look at some examples...
In the Rule #1 example below, I am showing two paragraphs without margins and then two with bottom and top margins that collapse. In the second part, the bottom of the top paragraph's margin has merged with the top margin of the second one. The margins collapse and the largest margin is used. In the nested examples below, the 'div' parent block holds child paragraphs which have top and bottom margins, as does the parent "div". These all would merge with top and bottom paragraphs outside the "div" parent normally, except the 'div' wrapper contains a border in the first instance, applying rule #2 above. We could have added text or a padding as well on the "div" to trigger the exact same scenario where its margins are honored. In the second example, because the "div" has no border or content, the child paragraphs push outside this parent and merge with the outer two top and bottom paragraphs and form one unified margin between them. Note that borders on paragraphs don't affect merging of margins as they don't have child elements with margins in this test.
Two paragraphs with NO margins are shown below...
The bottom margin of this paragraph is collapsed with the one below to form a single shared margin of 1em.
The top margin of this paragraph is collapsed with the one above to form a single shared margin of 1em.
Now, let's add margins to our paragraphs...
The bottom margin of this paragraph is larger (2em) than the one below so it "wins" and is used as the shared margin between the two.
The top margin of this paragraph with a 1em margin is collapsed with the one above to form a single shared margin of 2em.
Below is the code for the example above...
<p style="margin:0em 0em 2em 0em;background-color:green;">The bottom margin of this paragraph is larger (2em) than the one below so it "wins" and is used as the shared margin between the two.</p>
<p style="margin: 1em 0em 0em 0em;background-color:lightblue;">The top margin of this paragraph with a 1em margin is collapsed with the one above to form a single shared margin of 2em.</p>
Nested Margin Test: Now let's test Rule #2 above and how paragraphs with margins act inside a parent 'div' also with margins. Below, notice a "div" parent with child paragraphs has a blue border (plus margins). Based on Rule #2 above, because of this blue border, the margins of its children do not collapse with the outside paragraph's margin, but are maintained inside. The div's outer margin is still merged with the top and bottom outer paragraph margins, as normal. But its child paragraphs retain their own margins internally. The rules for collapsing margins say this blue border triggers margins to NOT collapse between the parent "div", its children, and any outside paragraphs. Only the div's margins have collapsed with the two outside paragraphs margins.
text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text
Another Nested Margin Test: Now let's remove the blue border and see how margin's collapse between the outside paragraphs, the div, and its inside paragraphs. Below, notice the "div" parent has NO border or content, even though it has margins. Its own margins have now collapsed to zero. The margins of its children are then merged with the outer paragraphs around its parent "div" so they now all stack with even margins. Margins have all merged. This shows how the "published text model" dominates how margins perform in HTML and why you must be aware of how and why this happens as you design content in HTML.
text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text
text text text text text text text text text text text text text text text text text text text text text text text
The reason this strange "margin collapsing" feature of HTML works this way is simple: HTML is trying to use margins to make text look like it does in old books. HTML does this by controlling how text paragraphs space lines of text, and with empty spaces between text, it has to assume the reader does not want to see extra spaces or margins between them. Now you know how and why HTML margins perform the way they do!
As quoted from Mozilla (https://developer.mozilla.org)...
Between 2011 and 2019, the median resource weight increased from ~100KB to ~400KB for desktop and ~50KB to ~350KB for mobile. While Image size has increased from ~250KB to ~900KB on desktop and ~100KB to ~850KB on mobile.
Why is that? The two reason are BLOATED JavaScript API's and new developers not understanding how to compress huge images they create for websites. The bottleneck slowing web page rendering is not "blocking" files like CSS, because most browser only allow 6 parallel connections to the server, anyway. The blocking mechanism is rise the past 10 years in HUGE SCRIPTING LIBRARIES AND IMAGE FILE SIZES!
We learned how to compress images like gif's using "Web Safe" 216 color palettes (created by Netscape) and LOSSY photo compress by image programs like Adobe's "ImageReady" 20 years ago. Developers today have completely forgotten how to do that. So instead, they've created bloated JavaScript and huge images that are never compressed or ever use reduced image palettes. It is sad we have failed to mentor the tech youth of today as the Internet has gone backwards by about 10-15 years as a result. Imagine how fast the Web would run today if the millions of images used today were coreectly compressed? Besides, bandwidth costs big bucks!
Also, most phones and new monitors have "HD resolution", which means the dot per inch is no longer 72 dpi on macs, or 96 dpi on Windows, as in the old days. Resolutions are not approaching 500 ppi (pixels per inch) on many mobile phones. Because web image now look tinier and tinier on these devices, the manufacturers have come up with their own "pixel" called a "device pixel" which is some percentage of the CSS or browser pixel. This ranges from 1:2 to 1:4, which means they take whatever image dimensions in pixels you set in your style sheets and recalculate it to larger numbers on their devices and screens so your image fits correctly. In addition, many users increase font sizes or zoom, the latter which increases pixel sizes yet again. The end result is, you often have to create multiple images.....one set for traditional desktops and another for these high resolution screen, like we see on iPhones today.
FILE DOWNLOADS THAT "BLOCK" ARE NOT A PROBLEM: Many developers today online are wasting huge amounts of time doing "pre-loading" of modules, preprocessing CSS, minimizing, creating scripted external file blocking tricks, compressing CSS and scripts, and using asynchronous calls to the server to try and squeeze out milliseconds of download time, when HUGE JavaScript payloads is the still the central problem in slow web pages in modern web pages today! Until they remove these inflated scripting libraries they shove into the browser (1.5 Megabytes of JavaScript on average with this new API's according to the Web Dictionary), nothing will improve. Until they realize sending 3 megabytes of scripts is wasteful and unnecessary when displaying a few lines of text for a reader to consume, nothing will improve in their web page delays and designs online.
Lastly, you want to consider using the new media image and video formats in HTML5 for those new browsers that support them and regular images for everyone else. The new "WebP" media type for images, for example, use a superior compression algorithm to assist in giving users faster image download times. The one issue is that older browsers won't know these new types. But the new "image" architecture I describe in this tutorial works well with fallback image designs using the new 'picture' element to help old and new browsers pick the type they recognize.
I better way to help you is to offer a new paradigm shift AWAY from Angular and React and BACK to lite-client architectures. This means going back 20 years to the ORIGINAL server-based web architecture we used to have, which they abandoned. Mobile phones really need this simpler server-based architecture anyway, and would benefit from the tinier downloads of scripts and images sent to them. So without going into details, if you want to increase the speed of all your web applications, my recommendations are:
Floating blocks (using a simple CSS property on a 'div' element like so: div.myclass {float: left;}
) was and still is a common way to create what are called "flexible layouts" (so-called "responsive" web page design). In a "floating layout" technique, 'div' blocks with content are assigned the CSS float property and allowed to stack horizontally next to each other as the browser's window width increases. Below is a simple example of a floating layout:
my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content
my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content
my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content
Honestly, we started building these types of floating and non-floating layouts almost two decades ago (c. 2000) and never considered them anything special. Browsers starting with Internet Explorer 4 supported floats and allowed us to start using them to build powerful layout designs. But floats remained buggy for years after that, including in Netscape 4, IE 4-6, Mozilla 5, and Opera 3. To address these issues, we designed cross-browser CSS sheets that addressed all these issues, including IE6 and its quirksmode and standard versions.
But those tricks were then lost but to be "re-discovered" by the new generation today who seem to have made it harder on themselves by not learning from the past. There is nothing new here to learn in articles online about floating layouts and "hacks" to control them but a reinvention of the same wheel built 20 years prior. But let's talk about all of those solutions and the original problem with floats again, as well as "flexible layouts", in general. I promise to give you a nice, rich set of choices on how to use and end floating layouts correctly that you can easily cut-and-paste into your web projects.
Despite the promise of flex and grids, those new CSS-driven techniques are still not fully supported by many browsers, even now in 2022. This still means "floating layouts" will be around for many years. But I will discuss flex and grids elsewhere in this page to give you a full set of options when laying out your web pages, as I do like the newer alternatives.
Floating "divs" as a layout technique is still a viable way to design web pages in HTML. If you choose to use floats (or a 3rd party product like Bootstrap's float-based layouts) keep in mind that a floating block's major purpose was by design to float images over multiple stacked text blocks in a "book page design". Floats were never intended for web page layouts. The floated items (often images) were created to stack up and over text blocks so the text under them could flow around them like traditional book designs do. This had been the norm for book design in the Western World for hundreds of years, btw. Web designers did not invent this. This idea of using floating blocks for images and text was a good idea initially, but meant the parent block-level element that held floats would have to collapse to zero height so text blocks could move up and under floats without gaps. Unfortunately, in using floats for layout structures that idea meant it was difficult to "end" a float set when the floated layout ended and a non-float followed after it. That is the problem you see below. The white content box actually sits in a separate parent 'div' from the one wrapped around the two floating ones. It should start on its own line as a block-level element, but it doesn't.
my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content
my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content my content
Why am I floating up here???
To fix this problem, web designers after 2001 started looking for ways to extend the parent element around the floats and contain them so when the parent ended a new block of content, free of floats, could begin. Keep in mind this is using floats in a non-traditional way. Floating content was never meant to manage exotic layouts in the first place. They were simply our next best option besides tables, which after 2000 most designers decided would never be semantically correct for layouts. Tables are used for tabular data, not layouts. So tables were abandoned long ago as layout tools. (That is why it is odd to see some young developers today returning to using tables to control layouts in 2022. We stopped doing that 20 years ago!)
These bizarre issues surrounding floats created HUGE cross-browser bugs and struggles in browsers of the past using flexible layouts (i.e. Internet Explorer 6). To fix this issue, most HTML designers either added "clear:both" to a lone "clearing div" at the bottom of the float or wrapped the float blocks in a parent that had certain styles that both contained and ended the parent container correctly. I have articulated various solutions below so you can try them all. There are many more you can Google that designers have created that also work. Browser support for these tricks vary, however, so be sure to test.
The floating layout examples below use colored boxes that sit side by side and stretch as the width of the browser changes (try it). This is a common layout structure. But notice the boxes below are contained inside a parent "div" that wraps around their changing dimensions (gray background) that has collapsed. This is generally what is expected for floats, initially, as the parent was designed to hold an unlimited set of text blocks and floating images inside that allowed text to move around them. In the old days of using floats for layouts, we debated whether such a container that wrapped around these floating objects for the sake of layout was even semantically valid. We resolved that by simply giving these "div" containers an 'id' attribute with a name like "wrapper" or "shell" so we knew what their strange structures represented. (So if you see those names in older website code, now you know why they exist.) Their purpose was simply to "wrap" around or contain floating layouts in older browsers for layout purposes only. That technique is still used today.
Wrapping floats in a parent container that ends the "float box" correctly allows them to move safely within a block-level element without overflowing into the content below. The examples that follow below fix this issue by ending the float and applying various CSS styles to the parent 'div' element that wraps around them and encapsulates them.
Below is a float whose parent does NOT contain them but the 'p' block-level element after them has used a simple "clear:both" style to start itself AFTER the floated block and end the floating problem. This still does not extend the gray wrapper parent 'div' around it's floating children, however. That remains the problem:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
This text now starts after the floats correctly on a new line because this text's 'p' element uses "style=clear:both" to clear everything before and after it.
The second and third fixes below finally solve the issue completely by putting CSS styles directly on the float container that forces the parent's box to wrap around its floating children and end the float. Look at how the gray parent box wraps correctly around its floating children. These have various levels of older browser support but work reliably in newer browsers. The last solution is my favorite and uses a "clearing div". It works 100% of the time in all browsers, old and new, and doesn't rely on any CSS "hacks". Its one disadvantage is you must manually drop in a line of HTML at the end of your float box.
Below is a float whose parent correctly contains its child floating blocks by using "overflow:auto" on its style, which now allows the parent to wrap around its child floats and non-float content. Note that "overflow" doesn't work in some browsers, or is very buggy. These problems still exist in IE 1-6, Mozilla 1-5, Netscape 4,and Opera 1-3.6. All later browsers recognize it, however. But using this property could create a scrollbar every time in these older browsers when using "overflow:auto". So be careful!
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
This text now starts outside the floats correctly because the float parent above has wrapped itself correctly around its child floats and ended the float block using "overflow:auto".
Below is a float whose parent does contain its child floating blocks by using a special CSS "hack" class on its style, which now allows it to wrap around its child floats and non-float content to begin after it. This solution relies on a couple special CSS2 ":after" and "content:" tricks that work in nearly all modern browsers. However, its weakness is some older browsers will not support it, including Internet Explorer 1-5, Opera 1-3.6, and others as they do not support those newer CSS rules This trick may have minor issues like spacing problems after the floats in a few browsers like Opera version 1-6 and old Firefox 3.5, as well. (I have not tested it recently in those versions) Note: You will see a version of this ":after" clearing fix in most websites today (2022). Use this for a CSS-only fix that is guaranteed to cover over most browsers out there today, understanding that older Internet Explorer browser will not support this CSS.
This "hack" relies on the following CSS class and "hack":
<style>
.clearfix:after {
display: block;
height: 0;
clear: both;
visibility: hidden;
content: " ";/* place this last in case it blows up in non-supporting browsers like IE3-5 */
}
.clearfix {
*height: 1%;/* only IE 7 or less see this */
}
</style>
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
This text now starts outside the floats correctly because the float parent above has wrapped itself correctly around its child floats and ended the float block using the CSS pseudo-class ":after" hack mentioned above.
Below is my favorite solution for clearing floats simply because it is so reliable. This is a very old clearing trick that has the advantage that it works in all old and new browsers going back to the 1990's including browsers built today. It ends the float reliably and consistently using a simple "clearing div" element at the bottom with very simple CSS styles applied. I like to create a small CSS class for this and apply it to the clearing div below. In the past I have used "clearing divs" reliably like this, which even worked in old IE5.5, 6, and IE5 for Macs. Despite the added HTML element, this is generally a superior solution as it works so well and doesn't require complicated ":after" pseudo-elements or CSS hacks, which some browser don't recognize. This version also gives the HTML web page builder complete control of when to end the block.
Internet Explorer Bugs: IE5 needs a style of "clear:both" on the "clearing div" below. If you add any other styles they trigger "hasLayout" in IE which gives the div dimensions and creates an extra vertical space at the bottom. This you cannot remove if you use any other style. IE7 conflicts with IE5 here as it has dimensions but needs a value like "height:0" added to its styles so its dimension collapses. But adding this value triggers "hasLayout" again in IE5, creating a space in its clearing div again. The solution is adding a simple HTML comment between the clearing div tags which triggers the "div" space to collapse after the floats in IE7, but does not affect IE5. Result? Both collapse now after the floats, as expected.
* Note: As reliable as this solution is, modern developers have two criticisms of it: First, it is not semantic, meaning the tiny "div" element used adds unnecessary HTML that has no purpose. That is true, but not a big issue, as the 'div' is hidden visually and has no content. Notice I have also given it an ARIA role of "none" so screen readers will ignore it completely. Second, they say its cumbersome to implement as now requires you paste HTML into your page versus a CSS fix that is easier to manage. That is also true, except the odd fact you had to manually add floating 'divs' to create your layout in the first place, so why not add one more? The ":after" pseudo-element actually adds non-semantic empty content (a space) to the HTML DOM tree, anyway! My argument in preferring to use the old-fashioned "clearing div" here is the fact it is so reliable and requires no CSS on the parent element. You will never have a browser fail to implement it. It also does not pollute your CSS with convoluted CSS "hacks". But in the end, I say, "pick your poison!"
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
This text now starts outside the floats correctly because the float parent contains the clearing element using a simple "div" element with simple clearing styles applied.
Good news! There is a new float feature called "display:flow-root" that solves all our float problems in 2022! Meaning: You don’t have to use clearfix hacks! Just add this CSS property to a class on the parent element that contains your floats and it will clear them at the end for you! The bad news it isn't widely supported by browsers yet :( But I thought I would add this if you plan to start using this new CSS property. My recommendation is you use BOTH this new property on your float parent element AND keep using your float clearing solution as before. Eventually your property will be supported and you can safely remove any CSS "hacks" or your clearing div from your HTML. Meaning: You don’t have to use clearfix hacks once its supported. Keep in mind that browser support is still dismal. Below are the browsers that still do NOT support this property. Basically, only the newest browsers minus Internet Explorer support its use.
Non-support of the new CSS parent float property "display:flow-root" in modern browsers is as follows:
Warning: For now, always combine this new CSS property fix with older "clearing fixes" because lack of browser support.
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
If your browser supports "display:flow-root" this text lies outside the floats correctly. This new feature as mentioned has limited browser support in 2022, however.
My point here is not to argue for a specific float clearing solution, or condemn this solution or that, but give you the options with their true flaws and benefits and you choose what works best for you. This more comprehensive example has helped me to see how and why floats do what they do and how to end them correctly when using the non-traditional floating layout.
The new 'data-' attribute in HTML5 is a powerful way to store text values inside attributes in any HTML element in your web page. They are essentially custom attributes you can name and use as you like! You can then add text values or "data" to them without worrying how the browser will interpret them or change your elements. They will not. So why use them?
To use them in an HTML element simply prefix your attribute with the word 'data-' followed by whatever text string you like (<img data-how-does-my-cat-feel="My Cat Loves Me!" />
). You can create multiple attributes of custom data on a single attribute. The 'data-' attribute is then used to store this custom data inside your HTML elements separate from the server. It is also private to the web page or application. They are ignored by browsers and do not change your elements design or function, but available for screen readers when they interpret the meaning of elements blind people cannot see. They also are a powerful way to store custom data associated with HTML and cache data used by JavaScript or other applications running in the page. You may see this technique is often used by Razer and Angular frameworks to tell scripts what to do with various elements separate from its content, toggle visual elements on and off, manage large tables of changing data, etc.
In the past we often used "id" for this technique, but it was not enough. The data stored this way using this new attribute can now be used to control visual design data, properties of the element, raw database information, or be used to temporarily store data in your page you change on the fly that is helpful when a database is not available. Below is an example of how to use multiple "data-" attributes this way. But always keep in mind, you can create any text-named attributes you like using 'data-' on any HTML element as long as you precede your attribute name with the "data-" prefix. Also, the attribute name should not contain any uppercase letters and must be at least one character long after the prefix "data-". Otherwise, the 'data-' attribute value can be any string you like, even hyphenated ones.
Note: As mentioned, most new and old web browsers ignore element attributes with "data-" as a prefix. So, these are very safe to use and easily accessible via JavaScript. It is one more reason to always use 'id' attributes (as I have mentioned) to uniquely identify important web page elements with data. The one bug in using 'data-' is the fact they will not be XHTML-compliant in some user agents and could prevent page validation using XHTML. But we are in HTML5, right? So for now, I recommend you still use them.
This text has many data attributes assigned to it that a script could manipulate or use to change the design, columns of data, etc.
The new WAI-ARIA recommendations in 2022 require semantic information about widgets, structures, and behaviors be assigned to HTML elements in order to allow assistive technologies to convey appropriate information to persons with disabilities. ARIA ('Accessible Rich Internet Applications') attributes add the semantics to HTML5 elements needed to bring a modern website up to assistive and accessibility standards.
Unfortunately, many of the new HEAVY client-side technologies kids today are building - thick JavaScript API's like Angular or React - have damaged accessibility for screen readers and other user agents that help the blind read web content. Due to manipulation of the DOM by scripts with non-conforming HTML or dynamic HTML updates, these API's create pages that are not seen by many readers.
To address these problems the "WAI-ARIA" accessibility standards were created to allow web designers the ability to add attributes to HTML5 elements and give alternative user agents like screen readers more information. For example, you can add "aria-" and "role" attributes to elements that tell screen readers what elements do, their roles, their states, or when a live scripted update has occurred. However, that will not fix the damage done to the web using these heavy client-side technologies, in my opinion. ARIA has merely put a band-aid on the problem.
I have included a sample of elements with roles and aria attributes listed below to get you started. As of 2022, support for these various attributes varies by user agent. You should be able to safely add them to your HTML, however, knowing they will NOT affect you normal web page views on phones and on desktop browsers.
These ARIA attributes come in two main "types": "role" and "aria-". The 'role' attribute must fit a specific WAI-ARIA text string. "aria-" is used for accessibility and must also fit a specific WAI-ARIA text string type following by a supported value. The 'aria-' attribute itself comes in two sub-types: Property type that is unchanging and State which changes based on user interaction. I will not cover those in detail here, simply because support by screen readers is so variable at the moment. But I will give you some solid examples of how I use ARIA and how to apply basic ARIA attributes to your HTML. You can Google them for more information online.
Here is a sample of major structural "Landmark Roles" you can apply to your structural layout HTML. They are predefined already in most browsers for the new HTML5 tags. That means when you use those new HTML5 elements, they imply these 'roles', so are optional. That is how ARIA really works...in most cases a screen reader will deduce your HTML and its content and purpose as long as you follow traditional HTML tag use. The farther you stray from that the more important use of 'role' and 'aria-' become! However, I feel its good practice to use them anyway.
HTML Landmark Role | HTML5 Element They Represent |
---|---|
role="banner" | <header> |
role="complementary" | <aside> |
role="contentinfo" | <footer> |
These attributes listed above become available for screen readers when they interpret the meaning of elements and read the attributes and their values. Most modern web browsers will ignore them. Note: The 'aria-' and 'role' attributes are supported in 80-90% of browsers in 2022. You do no not add ARIA "role" attribute for many HTML elements, now, like 'input' that uses "text" type, 'img', etc. as most screen readers deduce the correct role, anyway. The idea is not to fill your pages with every HTML element defined in ARIA, but to fill in non-traditional HTML with assistive attributes. Below are some examples to demonstrate that.
Here is a primitive navigation menu decorated with ARIA attributes to assist screen readers. Note the use of "menu" and "menuitem" here. Note: We do not add role="navigation" to the "nav" element as it is redundant and most readers will identify the "nav" element as "navigation".
Here is an example of how I use ARIA in some sample form input elements. Most screen readers will discover the correct meaning of your inputs naturally. The 'form' element, or the 'input' element with "checkbox", "radio", or "text" for 'type' will be known by most screen readers, so do not really need ARIA roles. Use of newer HTML5 custom input types, however, might not be known, so need extra help. All button elements default to a "submit" button type when the 'type' attribute is left off so must be conveyed to screen readers as buttons using ARIA. Custom "state" ARIA is optional on form controls (example "aria-pressed" or aria-checked="true") should be updated by JavaScript if used. The only other 'input' element "types" I may add roles for in practice are custom element 'input' 'types' like "email", "password", "number", "search", etc., or 'button' and 'input' elements that use 'types for "reset", "image", or "file". The latter might not be described as buttons and confuse a reader when engaged. Below I've gone ahead and added full ARIA attributes to the form control elements below so you can see how that is done.
Images are especially problematic for the blind. Most designers that correctly apply 'alt', 'title', and captions on web page images naturally assist screen readers interpret images correctly. Adding ARIA attributes just makes sure your images are fully expressed in many types of screen readers. An ARIA role isn't always needed on the elements below, however, as both 'figure' and 'img' elements are self-describing to most readers. Note that here, 'aria-labelledby' tells the viewer that the figure's text label is provided by the text in 'figcaption'. This is helpful in simplifying what a screen reader needs in describing the image and the elements that are associated with it.
Below is a good example of what you must supply to screen readers if you use "non-traditional" image wrappers and descriptions. Here the 'div' element and 'p' element have created a custom caption that visually looks close to the previous example. But in this case the designer needs a very long text description of the image that goes beyond what an image caption supplies. In that scenario the 'div' and 'p' elements are alien to the screen reader. So you need to associate them to the image, logically, using a full ARIA role and label setting to assist a screen reader that otherwise might not associate the image with those HTML elements
Larger description of my image and why I posted such an old weather image. Maybe I need to see what weather was happening in 2004?
One of the BEST places to use ARIA in assisting screen readers is in your HTML layout structure (the top-level HTML that organizes your web page). This is how I designed this page, in fact. Review the code below and check out how I have given the main structures of my web page an 'id', a 'role', and an ARIA label. I have also connected my 'section' of content to the 'region' role and then assigned its label to the 'h1' heading element. This allows a screen reader to quickly identify the page's main content and get right to your content quickly. It also makes your HTML layout structure easily identifiable by JavaScript API's and more easily manipulated, if needed. As mentioned, most readers will derive the correct 'role' of your HTML from these new HTML5 element names, like 'header', so are often redundant.by I like to use them in case an older HTML4 screen reader still struggles with my content.
Most HTML anchor elements in your web page are identifiable by screen readers based on their element type so do not need roles. Anchors are one example. If you use any non-traditional element as a link then it does need the "role=link". The anchor element 'a' always implies that semantically.
In general, I do not yet use the new ARIA "state" types like 'aria-live'. Many of these attributes are still not fully supported in screen readers. Others require immediate JavaScript updates to the 'aria-' attributes you add so screen readers see what has changed as the scripts manipulate the HTML and DOM dynamically. If you are using heavy JavaScript API's, like Angular, for example, then identifying much of your content as "live" as you change those areas on-the-fly is critical to screen readers. In those cases you might need to design and build a dynamic "ARIA state service" to apply ARIA "state" to HTML elements as you download and change the data. Below is just a starter example of what a "live" ARIA attribute set might look like. The rabbit hole goes much deeper from there!
Link Example #1: This link does not need an ARIA role
Link Example #2: Note: This button actually links to a web page. So it does need an ARIA role as it is not a typical hyperlink element.
Changes to dynamic content by JavaScript needs to convey that to screen readers on a block-level and atomic level. Using 'aria-live' helps. 'aria-atomic' tells the screen reader to only update the element if something has changed inside it, not the larger parent block that contains it.
A Random quote: JavaScript might insert live data here using an XMLHTTPRequest request call. But the screen reader would not know it has been updated unless its flagged as a "live" content element.
As mentioned, support for ARIA is still evolving today, so use ARIA attributes sparingly unless you are targeting and testing your website in a live screen reader of your choice. I am certain in that case your ARIA attribute designs will radically change and need to be beefed up. But my suggestions above will at least start you down the path of making your site ARIA-friendly. Below are a few "Best Practices" to follow when using ARIA.
Many new HTML5 elements such as 'nav', 'article', 'main', and others have default implicit ARIA roles assigned and so do not always need explicit identifying attributes (like role="article", for example). So adding "roles" to those elements is optional. But this rule also applies to most HTML you use. A good screen reader will know what you intended by the HTML choices you make. The problem is many developers do not always follow standard HTML "Best Practices" or element design, so in many cases, adding ARIA is important. This goes back to why I recommend clean and fully attributed HTML that is XML-compatible. I still add ARIA to all my top-level HTML elements and then "sprinkle" additional attributes in child elements where I feel it might help. The exception is "aria-label" and "aria-labelledby" which really are useful in telling a reader what your element does or contains. But do not overdo that. Keep the text in those labels short and sweet!
Use the ARIA "role=group" attribute for any generic element that wraps around a series of children that are all related but where the element and its content will not need to be indexed by the reader as part of its critical text content. For example, a 'div' element that holds a series of links or images would be a good choice for 'role=group'. 'group' tells readers not to index that content and that the grouped media is part of a "user interface object", not as text content. So the defined blocks will generally not be added to a "Table of Contents" a screen reader generates about your pages. So be cautious in what is defined as a 'group' role.
Use "aria-label" to give a textual description of what the element's content says or represents. But limit labels to major structural features, buttons, text blocks, menus, and links only, when possible.
Use "role=presentation" for any structural 'div' or element in your HTML that represents "layout", design, or presentation only. This tells screen readers to ignore large blocks of images, headers, designs, and other features in your web page that are only there to form a layout or visual design element in your web page.
Because images and other elements are usually self-identified as such in screen readers, you do not need to assign images the ARIA "role=img" or "aria-label". The 'alt' and 'title' attributes, plus the 'figcaption' element, when used, will give screen readers all the information they need about your images.
Avoid "implied" ARIA roles on MOST HTML5 elements as most are implied by the tag. Example: ARIA and screen readers know a 'tr' is a table row, as they do 'video' is a movie, etc. This means most HTML elements will have NO ARIA role applied. Those that do, usually are needed to describe a generic HTML element like 'a'. 'li', or 'div' that is holds special data or performs like a table, link, menu, or other feature and so need "role=menuitem", etc. to help screen readers identify their purpose beyond their ARIA generic or "none" element role.
You should still avoid dynamically creating JavaScripted custom HTML or objects that have no real semantic meaning or content value. If you are creating your HTML dynamically be sure you decorate them with ARIA attributes so they give readers some understanding of what they do and why they suddenly appeared.
It is important you style images correctly! Images, or 'img' elements, are actually "replaced" or embedded content in the browser window, meaning they are not connected to HTML but added as controls into the page by the browser (often from image controls connected to the operating system). For that reason, like 'select', the 'file' input type, and 'textarea' elements, they cannot always be styled by CSS. In older browsers, controlling images in an 'img' tag was sometimes difficult. However, 'img' elements have over the years been more "stylable" than say the 'select' replaced element in browsers.
There are several tricks you should always remember when designing images. Let's cover them now.
Image 'width' and 'height' Attributes: Today in 2022, most designers now set "width" and "height" on an image using CSS style sheets, not using HTML attributes on the 'img' tag. In the old days, we did the opposite and always added width and height using the 'img' element's natural width/height attributes. We often scaled those values up or down numerically in size as needed. This then precluded the need for CSS to change those values. The browsers back then would then honor and interpret those attributes values exactly as is and resize the image accordingly.
<img src="myimage.jpg" alt="image:My Image" title="my cool image" width="250" height="100" /
Today, with HTML5, that width/height HTMl 'img' attribute design has changed and in a subtle way most web developers fail to understand. Adding CSS image size overrules 'img' attributes as they have always done, such that 'width' and 'height' image attributes were always considered fallback sizes. In HTML5, however, image element 'width' and 'height' attributes are not interpreted that way in modern browsers. Prior to HTML5, image 'width' and 'height' attributes were used to define both the space for the image in the design and the actual width and height of the image. HTML5's current working group then came out and said, "The dimension attributes are not intended to be used to stretch the image". This then changed how width and height would be interpreted in browsers today.
It turns out that you must still use the 'width' and 'height' 'img' attributes to define the placeholder for the image in your HTML block, but now must use CSS to control the images final width and height. If you do not use either, the browsers will still try and figure out the right dimensions or actual size of the image, but often will pull the images native width and height to calculate an 'aspect ratio'. One of the "weird" aspects of this shift is that you cannot always "stretch" a image larger or smaller from its true size using width and height attributes, as before, as such 'img' attributes are now "hints" in HTML5 as to what the interpreted final width and height of the image will be, not concrete values to be honored. The browsers now use your 'img' values, the CSS values, and the actual image's dimensions to "calculate" its final dimensions, then creates a style representing this value. It does not honor your 'img' attribute sizes. I will now show you proof of this below:
HTML5 Does Not Honor the Image Element Attributes 'width' and 'height': Below I have added an image with its 'width' and 'height' attributes "resized" to a custom value of 510 x 400 pixels, twice the actual size of the image which is really 255 x 200. I have also added a JavaScript popup alert box so you can see what value the script actually pulls for the image's width value. In addition, I have added a class that clears out the styles on the image using all:revert
to see if the script pulls the same width and height even after clearing any custom styles applied.
Here is the HTML I created for the image below. Notice, I set its custom 'width' and 'height' and added a simple JavaScript trick to pull its width from the image element. Now, click image to get the width!
<img id="imageresized" src="www.jpg" width="510" height="400" alt="" onclick="JavaScript: alert(this.width);" />
Why is the 'width' on the image '255' when my width attribute says '510'! Why does JavaScript report it is changed to '255'? The reason is the HTML5 browsers ignore your dimensions now and "calculate" the dimensions it thinks you want! These dimensions are from the actual images width and height, not the larger ones you added to the 'img' tag.
What is worse, all Internet Explorer browsers (IE1-11) will honor your original attribute dimensions and 'width' will be "510" in those browsers, the value you expect. Again, this shift is from HTML standards groups who have shifted the meaning of image attributes, calculated aspect-ratios, and their affect on final image dimensions.
In this case, erasing the styles on the image using "all:revert" erased the "calculated" styles the browser first made. It then recalculated the dimensions again using the actual image dimensions, not the custom ones you originally told it to use on the 'img' tag. What's happened is the new HTML5 standards have asked vendors to no longer honor the width and height attributes, but "calculate" the new width and height based on "hints" to get an aspect-ratio and then create width and height in CSS in memory from that calculation. In other words, the 'width' and 'height' attributes should be used to describe the source file, not how you the designer want it displayed. When I used "all:revert" to reset the styles, I destroy the calculated value that overwrites the HTML attributes, so even JavaScript pulled the wrong value! But the browser erased the 'img' attribute width and height values I originally set, simply because they are "hints" now. So my width and height are gone!! In other words, in HTML5 now, you cannot retrieve the ORIGINAL 'width' and 'height' attribute values you set as they have been used as "hints" only. Crazy!!
The actual purpose of the 'width' and 'height' attribute values, according to the new HTML5 specification, is to inform the browser of the actual, intrinsic width (in CSS pixels) of the image file itself, not set its dimensions. For that reason, I recommend you ALWAYS set 'width' and 'height' 'img' attributes to THE ACTUAL WIDTH AND HEIGHT OF THE IMAGE ITSELF, as that is how it will be interpreted in most cases by default before you style it. Old IE browsers will still honor those "stretched dimensions on images as is and stretch the image based on those attribute values if they are different from the norm. But newer browsers are not allowed to do that now, and will reset them back to the images native values, regardless of attribute values. If you want to customize image size, you now must do that using CSS and a class, not using width and height attributes, as in the old days. The browser in HTML5 has removed it and re-interpreted it to a CSS custom value. If you want to "stretch" your image you are stuck with CSS now, which now is the only way to override the browser's "interpretation" of 'width' and 'height' set on images. Below we will look at how to create "stretchable" images that override that new HTML5 feature and which are "responsive" as needed.
Should I still set Width and Height in the Image Tag? Yes! It is still important you set 'width' and 'height' attributes today in images in all your web pages, as those attributes tell the browser's parser and "RenderTree" to reserve a space for images in the document tree (DOM) at those sizes in the unpainted viewport layout as the images download to the browser. Doing so, the user can start reading content without the layout shifting on them or the page refreshing or repainting the viewport. Otherwise, the layout shifts as the image downloads, moving content around. This happens a lot with floating images in text blocks. For that reason, I always recommend you put width and height on the image, but simply use the images native (actual) width and height (right click an image and choose "Properties" then the "Details" tab in Windows to see its actual size).
The 'alt' Attribute: The 'alt' attribute is a text "replacement" for the image when it is slow to appear, fails to appear, or not viewable by the blind in a screen reader. 'alt' text should describe the image if the image contains information that is important to a screen reader. If the image is wrapped in an anchor (a hyperlink) the 'alt' text should explain where the link goes if the image is clicked. You can also use an alt="" blank value if the image is only for decoration. This tells screen readers the image is not important and if its missing, no placeholder will create a empty image box. I like to use the following format for the 'alt' attribute: "alt=image:a short description here" if the image is non-presentational (like a photograph) as it tells me the placeholder was for an image, not video or other media, and what it represents. I also like to place a slight gray background behind my images, which allows you to see the 'alt' textual placeholder in the block as the image downloads. As mentioned, the 'alt' attribute is also vital to screen readers.
The 'title' Attribute: Always give your images 'title' attribute text, especially if click-able or inside a link. This allows users to rollover an image to see where it goes or what it represents. DO NOT DUPLICATE the 'title' attribute with 'alt' text, however, as screen readers may repeat the same text when reading those attributes. (I used to make that mistake as a developer). Never use just "image" for text in either attribute, but give it a description that's unique. Use of "longdesc" with a URI link was once used alongside 'title' to provide a link to more detailed information about the image. But this attribute is now either experimental or deprecated. Most use the new 'figcaption' feature to describe the image.
Adding Rich Captions to Images: The 'figure' and 'figcaption' elements are now used by modern browsers to wrap around images and add captions beneath images in HTML5. The 'figure' element warps around the image and the "figcaption" usually appears under it with text describing the image. Most photographs or article images should carry more visual information in the 'img' element as well as the 'figure'. In the sample below, I demonstrate an 'img' element with a full suite of attributes that assist users with screen readers, 'title' rollover text, and a 'alt' placeholder text as the image downloads or if its missing. Other attributes assist the image in other ways. The 'figure' element has formatting that enhances the frame of the image in the article, and the 'figcaption' allows us to place a nice caption on the image. Notice the image has its native width and height attributes added. This allows the "render tree" in the browser to reserve space for the image in the viewport as it downloads. It prevents the layout from shifting when the final image appears in the element. By default in HTML5, as mentioned already, browsers only use these 'width' and 'height' values as "hints". So, going forward its better to place the actual dimensions in those attributes, rather than large or smaller ones as its likely the browser will default to the actual dimensions, anyway. Finally, adding ARIA-friendly attributes connects these elements more closely to the image. But notice I have not overdone it! An good example of how best to code HTML images is below.
Sometimes designers want images with even greater descriptions. For larger image descriptions use this format below with a 'div'. This is also compatible with WAI-ARIA accessibility standards, which will read and associate your container 'div' and your 'p' description with the image. Notice the "role=img" added to the 'div' element to associate that element with the image and caption grouping. Since the 'div' element, unlike 'figure', is not normally associated with an image, this helps the screen reader identify the div container as part of the image. Below is a ARIA-friendly version of that idea.
longer description longer description longer description longer description longer description longer description longer description longer description longer description longer description longer description longer description longer description longer description longer description longer description.
The JavaScript 'onerror' Event in Images: If an image is not found or missing, you have a choice: Either let the browser show a broken error image and hopefully your 'alt' attribute text replacement, or use JavaScript to degrade gracefully and hide the error. You can use a trick like this: "onerror=this.onerror=null; this.remove()" when an image is missing, corrupted, or slow to download. The latter removes the broken image and the image itself that's missing and would show nothing, removing the image box. If you don't want to do anything when a missing error occurs but show the 'alt' text in a box, call this simpler version: "onerror=this.onerror=null;". If you want a "default" image, do this: "onerror=this.onerror=null; this.src='default.jpg" and add a new default replacement image. Below is how the code looks:
<img src="myimage.jpg" alt="image:My Image" onerror="this.onerror=null;this.src='default.jpg" /
Responsive Image Sizing: In HTML5 in 2022, "responsive design" is all the rage. But we have been developing and using responsive design concepts in websites since 2001! Below is an example of a more modern "responsive" image size that stretches to fill the viewport. Actually, it stretches to fill the parent container that controls its size. The parent 'div' has a style with "width:100%". Notice I removed the images width and height attributes so the browser defaults to the actual images native size initially before it recalculates the new image size. I recommend you do that only on images and media where you want the image to fill a flexible parent box. The image now honors the more "reflexive" CSS sizing added directly on the image. So, I've set its width to 100% of the container's width. Leaving height "auto" allows the aspect ration of the image to stay the same, the height changing as the width changes. As the browser window shrinks or grows in size, the container div's width changes and the child image changes with it to fill the new size. This is a powerful way to control image sizes in CSS that responds to the various sizes of newer viewports on different devices like iPhones and tablets where both the device and its orientation now change. Images in this scenario would stretch to fill that void. This concept also works naturally in old browsers like Internet Explorer, too!
Note: More advanced responsive design techniques are now used in HTML5 where specific image sizes and resolutions are downloaded using media queries as the size of the viewport changes. This allows your site to download specific media targeted to a specific viewport or resolution on a device. The disadvantage is of course, you are downloading multiple images now, when one can be easily resized. In some scenarios, like phone web applications, this idea becomes more critical, however. (See the "srcset" attribute section below or go to my "picture" section for more advanced image source download techniques like this). Along this vein of thought, for years I have designed all my websites with "print-friendly" versions. To accommodate that, I always download a 300dpi high resolution logo image as a replacement for the web logo version for my users when they print a web page in one of my sites. This allows printed pages to print beautiful high DPI versions of images your website when printing.
The Best Way to Constrain Images to One Shared Size So, what if you have an image, but need it to be a different size than its normal one? Obviously, you would use CSS to do that. But what if you had multiple images with unknown height or width, but wanted them to all be "constrained" to one width or height along one dimensions? This is a common practice in HTML where photos are downloaded and replaced into a block-level element. There is a right and wrong way to handle this. Below, is a set of images, where the width is always the same but as new images are used to replace the image (via scripts) the height is flexible. Notice this also makes sure if images have differing "aspect-ratios" those are strictly maintained. This technique below does not require newer HTML5 CSS tricks and so works in old and new browsers reliably. Note: I always give images their true explicit width and height, now that HTML5 demands it. I then override that with a CSS style.
New "srcset" Attribute: Another form of responsive design is to deliver several images in various sizes to viewers based on the viewport. Typically we do this by media queries showing and hiding larger blocks of HTML and images. But if you had multiple versions of say a company logo at different size, you could switch the image out with the new image. To do that you can use the new "srcset" attribute in the 'img' element. The "srcset" allows you to list multiple images to download based on viewport widths. Below is an example where "1px" and "2px" represent a "device-pixel-ratio" often set by the device on high resolution screens like smart phones. Often devices use such high resolution screens that web sites and images created at a regular dimension (96 pixels per 1 inch, the default for 1x) look too small. So they redistribute a typical image and website dimensions into 2 pixels or more on their devices. "2px" below means you can safely deliver an image the same size but twice the resolution to that device. I personally think multiple image calls to the server for multiple images is wasteful here, but in some cases (photography) a high definition image delivered to a "2x" or "3x" device is quite a powerful presentation on those HD screens. Of course, cross-browser issues arise with this technique. No Internet Explorer browser supports this attribute and Opera-mini fails to implement this on mobile devices. But you can count on the 'src' image attribute still working in all browsers, so I support this as a "best practices" HTML5 option. Note the various alternative images below with their respective "device pixel" support or "maximum widths" needed to trigger their download and display on any give viewport width. The default here is always the "small.jpeg" image.
<img id="photo3" src="small.jpg" srcset="small.jpg 1x, large.jpg 2x" />
<img id="photo3" src="small.jpg" srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w"" />
Using Background Images: Background images are becoming more popular. In the past, we traditionally only used these when needing "tiled" web page wallpaper backdrops or under headers at the top of web pages. If used to show visual queues like photographs in pages, it creates a problem. The issue with background images is background images are not part of the page layout so "semantically" not viable. Screen readers certainly would not have a way to know about these visual queues like they would traditional images in 'img' tags with 'alt' attributes.
This means that there is no traditional image element to represent them in the HTML, which can cause a mismatch between the visual and the structural meaning in your website. This makes interpretation by various user agents for the blind very difficult. And so, I generally do NOT recognize the 'srcset' attribute on images as a good choice for image placement in websites unless its a presentation-only choice and tiled in the background. Some developers will argue it solves how images fill layout spaces, which the 'img' element can at times struggle to do. They then create complex polyfill solutions or padding hacks to simulate this in older browsers. But I argue back, so what is the real reason to use these? There are always alternative ways to doing things in CSS and HTML. Images using the 'img' tag still represent "best practices" in image use. However, if you want a clean example of how to use background images that is cross-browser compatible, I've created a 'div' container below with a background image example for you.
Below is an example of "responsive" design using background images. Notice, the block-level element below has a set height, but it's width is flexible. The background image uses a new property "background-size:contain" which tells modern browsers to always honor the actual aspect-ration of the image regardless of the parent container's dimensions. The photo will not distort but shrink in proportion to the container, even though it might not fill it completely along some dimensions, as the browser window changes. The blue background color shows that missing background space.
Cross-browser problems in Background Images: Because only IE9 and greater support "background-size", older IE browsers will not stretch the image from its original size to fill the parent container as expected. IE 5-8, for example, will show the image in its original size regardless of the containers dimensions. Another problem in older agents is the fact that using these empty containers without content causes the container to collapse. In IE8 you will see this problem. So an empty image "spacer" has been added to prop up its height for IE version 1-8. There are "hacks" to address the background image size problem in older browsers, but as always, my strategy in CSS and HTML layouts isn't to fix these visual issues, but let these browsers show what they can, and degrade gracefully.
Just prior to HTML5, web browsers introduced the ability to accept media files and images in "pre-encoded" byte streams directly pasted into HTML in a format called Base64. Without going too deep into what this encoding scheme means, its basically a way to truncate numbers into a smaller chunk of alphanumeric values that when read, represent the original byte codes for an image. Why would you do this type of things, say, for images? Well, not too long ago, some developers had the idea they could save HTTP calls to the server by sending the bit streams of images coded into the HTML of web pages. These extra connections happen in web browsers every time they pull down an image. By injecting the actual compressed byte code of the image into the browser (or into a CSS style sheet), they had the idea it might save thousands of calls to the server for websites that have lots of images (like icons or font glyphs). Not too long ago, browsers came with as few as 2 default open connections to the server, which at times meant delays waiting for images to download. These connections had to be shared with all kinds of other files as well, like HTML pages, scripts, media, etc. So, the Base64 image code was used to try and install image placers directly into the HTML.
You can see what these long Base64 encoded text strings look like by viewing the code below for a simple 118 x 118 pixel image I created. To create the Base64 code below, you can utilize dozens of free services online that will extract this Base64 code for your images quickly. You can then paste it into the source for images, or as I have done, into a 'div' element as a background image using the new CSS3 "data" type:
* If you cut and paste the code below into your HTML page, you will recreate my exact image above in your web browser.
For websites that had hundreds of small images in them, like icons or emoticons, this technique really worked well with Base64 injection, as you no longer needed to keep these images on the server. You could just send the browser the full library via scripts of hidden HTML blocks, and call then quickly with zero download time. The problem has been that often in larger images, Base64 encoding INCREASES the size of the image from the original. Browsers also cached images after the first download, so this idea because wasteful and consumed bandwidth, much like JavaScript API's do today. Avoiding the caching ability of web browsers is always a mistake and one of the serious flaws in kids today trying to invent new tricks and scripts that fail to utilize built-in features of web browsers used by the rest of us to advantage the past 20 years. In addition, with the advent of HTTP/2 and multiplexing, we no longer need to worry about downloaded files or connections. Browsers and servers have become incredibly efficient with managing connections and delivering hundreds of files quickly to the browser over the wire. In addition, up to 6 connections or more are the default pool of connections browser utilize today (instead of 2). So browsers no longer benefit as they once did with Base64 images. The other major issue is that older browsers that does not support CSS3 would not recognize the new "data" format for these new encoded background images, so would fail. This generally means any browser below Internet Explorer version 8 would fail, as they would not support Base64 encoded images. The advantage of using this newer technology (like many others invented the past decade) once again fails.
But, if you have a website where you have lots of libraries of tiny image files, it might make sense and speed up download times when encoding them in Base64. But, it's unlikely to make a major difference in speed simply because many of those images will not be used when first displayed.
Before we talk about the new <picture>
element, there are two new image formats you should be aware of that are coming in HTML5.
The new Image Formats: JPEG 2000, JPEG XR, WebP, and AVIF: There isn't wide support for them yet. JPEG 2000 is not widely supported in web browsers, except for Safari. JPEG XR was only supported in Internet Explorer 9-11, so never adoptted by the other browsers. Two of the new image formats, WebP and AVIF, are proving in tests to be fast, highly compressed image types for the web that have promise! Combined with the new <picture> element, it's now possible in 2022 to expand upon the old 'img' element as "universal image holder" and use it to display new image alternatives on the web. These two new types will never replace the 'jpg', 'gif', 'png', and others, but just give us faster web image alternatives.
The WebP format was introduced about 5 years ago (2015) by Google, but was not widely supported until 2020 when Apple's Safari OS browser adopted it. But sadly, it is still too soon to use it, in my opinion. AVIF support currently only includes the Chrome Webkit browser, but larger support is coming in the next few years, I am told. So, be prepared for a long browser support delay there, as well. In the mean time I'm sharing a possible HTML5 design using WebP for you below if you want to start using the <picture> element with WebP image types. You now have a nice picture structure you can start with.
The <picture> Element In Action: Below is an example of the 'picture' element with three image types: 'webp', 'gif', and 'img'. If the first 'source' element is not recognized (WebP), the next source element is tried (GIF). In this case it normally would be another alternative like 'AVIF'. But here I have added a GIF image. If that image type fails in the browser or the 'source' element is not recognized, the JPG image is used in the 'img' element. I have added a new feature to this strategy that shows you additional possibilities. See the "media=(min-width: 800px)" in the second 'source' element. This says to use the GIF only if the user's viewport is 800 pixels or greater in width. If the user's browser window is reduced in size and the modern browser supports 'source', the GIF image is never displayed. If no source element or image type is recognized in the first two choices, the 'img' default JPG image is used. The browser will normally go through each 'source' tag, image type, and media query rule and try to download the WebP first. The 'source' element's 'srcset' attribute merely overrides the 'src' attribute of the 'img' tag at the bottom. They do not act as full 'img' tags, only source image alternatives to the 'img' tag. If the 'source' elements or their 'types' are not recognized, the 'img' 'src' image will be used instead. If the any of the three images are recognized as types, but fail to download their specific images, the 'img' element's 'alt' placeholder text is used as a fallback and appears in an image box as text. Notice the 'title' element is also shown on rollover of the image even if the WebP image source is picked. Any errors downloading images of any type will NOT trigger the picture element to "try" the next source image. That's an important distinction! This is an error on that image tag only and the 'alt' text and a blank image will be shown in those cases, not the default 'img' image.
Additional Notes on 'picture' Element: Notice below I have created a nice 'alt' placeholder name when any of the images fail to download. All three image types above use this when they fail. The placeholder name of the image helps the user so they know what the image represents visually. Keep in mind, this multi-image design is a fallback for missing images or image errors on all three types, but not a way to handle 'source' tag and image type support.
None of the Internet Explorer browsers support the new 'picture' element, unfortunately. But you can see how this system works in a non-supporting browser by opening up "Internet Explorer" as a browser and viewing the image below. IE doesn't know what WebP or 'source' elements are. In IE, the first two source images are never used, even though the GIF type is known by IE. This is because the two 'source' elements are not recognized by IE. Even when the browser window is reduced in size to trigger the media query in the first tag, the GIF is not shown in IE. Only the 'img' JPEG is shown, as again, IE doesn't support the 'source' element. In newer browsers that do support 'source', if the WebP is supported it is shown until the browser window size triggers it to look at the next source element. If source was known but not WebP, the GIF would be shown in all window sizes. The GIF image type here is shown as it is universally known to old and new browsers. This shows how you can mix and match both image types, sizes using media queries, and the default image for older browsers. It is up to you to use this new picture element and various sources for various window sizes creatively.
If you see a "flowering tree" below, your browser supports the new WebP image format! If you reduce the browser window size and see the weather map, your browser supports WebP, but also the new media query in the source element. If you see the WWW image your browser does not support either the 'source' element or WebP. In the example below, older browsers will ignore the 'picture' and 'source' elements and read the 'img' element. Newer browsers will choose the WebP unless they still fail to support the new image format, but then will choose the WWW 'img' image like older browsers as fallback. So this solution is cross-browser compatible. The browser support is not available for many older browsers, but with picture's nice fallback mechanism, older browser would still receive the default 'img' image. This makes use of the 'picture' element for images a "best practices" HTML5 solution I approve of and which you can start using today! ARIA: Because images are usually self-identified as such in screen readers with 'alt' and 'title' supporting text, you do NOT need to assign your images ARIA roles and labels below.
Note: This new 'picture' element below is wrapped by the new 'figure' and 'figcaption' elements just like 'img', 'video', and 'audio' elements in HTML5 now use. The 'picture' element itself does not display anything. It merely provides a context for its contained img element that enables it to choose from multiple URLs. The picture element is a "container" which provides multiple sources to its contained 'img' element. In that sense, remember that the 'img' element remains the primary conveyor of images, not 'picture'. Note: Older browsers (IE 4-8) see 'figcaption' as a new unrecognized HTML5 element. Older browsers that do not know these elements will default them to "display:inline", pushing caption text to the right of the image. You can use CSS to address this by adding "display:block" to the 'figcaption' and 'small' elements as I have done below, if you support these older browsers.
* Note: My host provider does not support "WebP" images I found out, so if no "flowering tree" WebP image appears, it is not the code but my host provider. :(
One the MOST important aspects of this tutorial is the practice of good cross-browser design. "Cross-browser" means many things. But in the HTML5 world it should mean making sure your HTML and page layouts work in as many OLDER browsers as possible! Too often, I see young web developers struggle with this concept and simply hack their way through the problem using gigantic JavaScript polyfills, Bootstrap, JQuery "hacks", IE conditionals, Modernizr, or some other circus trick. All fail miserably as good solutions simply because they rely on added layers and layers of scripts and DOM patches, creating convoluted "Frankenstein code" to solve what are very simple problems that older HTML4 and CSS2 used to solve.
Its very easy to design HTML5 cross-browser solutions that work in multiple agents today. Why? Its been done already! Designing your multimedia displays in browsers with HTML need not be so complicated if you but look to what came before. The work of talented coders of 20 years ago already solved this problem for us!
Let's now take a look at an example of cross-browser HTML video displays from the past. In the old days, we realized that the 'object' tag would always be a unique element used mostly by Internet Explorer and its ActiveX implementation. And we saw that the 'embed' element was not going away. It would grow in popularity in support of Netscape, IE for Mac, Mozilla, and many new browsers that were coming on board in those early days. The reason 'embed' was popular was simple. Most browsers, their plug-in architecture, and their scripting capabilities never fully adopted 'object' and had picked 'embed' as their primary HTML multimedia tag of choice from the start. And yet, IE 5.5 and then 6 had come to dominate the browser wars as the years passed by. IE was what mattered most. This meant that in the early days of multimedia players in browsers, we were stuck with a very bipolar environment as far as HTML and tag support of multimedia. To solve this problem, some clever old programmers designed a way to combine the two elements and create a fully cross-browser framework that supported the two multimedia HTML elements: <object>
and <embed>
.
Below is a sample structure that was quite common back then. It is quite simple in how it works: The parent 'object' tag is read by Internet Explorer only, while the 'embed' child tag is read by all other browsers. The two tags support video display using a path to the video and various supporting parameters. This code design was quite powerful and supported IE as well as every other browser in displaying videos, audio, and Adobe Flash. Its use of 'object' and 'embed' work together in a "fallback pattern" that initially supports IE's ActiveX object control, then falls back to 'embed' and the common players and plugins supported by all the other non-Internet Explorer browsers. If neither tag is supported, it displays a simple "no support" text message. This example below used an Adobe Flash object that worked in nearly all web browsers, back then:
<object
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
codebase="
http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#
\version=6,0,40,0"
name="mymovie"
id="mymovie"
width="300"
height="200"
data="flash.swf"
type="application/x-shockwave-flash">
<param name="movie" value="flash.swf" />
<param name="type" value="application/x-shockwave-flash" />
<param name="play" value="true" />
<param name="loop" value="false" />
<param name="quality" value="high" />
<embed src="flash.swf"
width"300"
height="200"
play="true"
loop="false"
quality="high"
pluginspage="http://www.macromedia.com/go/getflashplayer">
<noembed>Your browser does not support
this media object found or the embed element.</noembed>
</embed>
</object>
This HTML pattern was quite common in 2000 and up to around 2010 when HTML5 browsers came on the scene. We often just pasted this code into our HTML whenever we needed any kind of custom multimedia display, like video, and it worked cross-browser pretty well for years and years. Eventually we ran into the same problem we have today: Which media type does each of my users support? No one ever really knew as it changed constantly. As Microsoft Internet Explorer began to fade in popularity with its ActiveX dominance, this media situation got worse. With open source video, Quicktime Apple movies, and Flash, it was difficult to reliably send every browser and platform the video type they needed. The player support in browsers just got too complicated.This HTML pattern certainly helped solve the markup issues, though. The media support issues remain, even today. Around 2008 someone got the smart idea of avoiding all proprietary codices and dropping movies into a new Adobe Flash video format, creating "FLV" movies as a one-stop, fix-all, universal video playback solution. We then simply pushed are moves easily into the FLV format and HTML code above and it worked well, for a time. But as support for Adobe Flash died on mobile platforms (after 2012), it soon became apparent the "plugin model" for multimedia display would never work. And that is how we got to HTML5 and its "playerless" 'video' element support for multimedia today.
It is 2022 now, and HTML5 is the newest rage. The HTML5 element for playing videos in a web page is the <video>
element. The beauty of HTML5 and the 'video' element is the fact that the browser is now required to have all the tools to figure out how to play the video. They no longer have to install or download a plugin or player. In the old days, we used to rely on every browser on every device to figure out how and where to get a video media player. Often the operating system had final say, not just the browser. On Microsoft Windows it was easy...in their Internet Explorer they relied on ActiveX and Windows Media Player to embed a player in the browser and play the media. ActiveX often was pre-installed and had vast powers behind the scenes on Windows computers in how video and audio was played. The same went with the Flash Player. The operating system installed it. Other browsers used different players and different solutions. This meant modern browsers had to manage loads of players and strategies to support all the media out there. And so the 'object' and 'embed' dual solution above mattered. With the new 'video' element, it does not. Today, the player world is dead. In 2022, the HTML5 standards groups have asked modern browsers to support the HTML5 'video' and 'audio' elements natively to support movies and music in websites and web pages. The problem is, many still do not support a wide array of video codices.
The same problems remain concerning cross-browser media playback in 2022 using newer HTML5 browsers. In addition, what might work great in many newer HTML5 browsers will not work in older browsers, which do not know what the 'video' and 'audio' elements are, nor support the newer media types or codices. Many, like older Internet Explorer versions (1-8), still must fall back to using the old ActiveX controls using 'object'. Other browsers still need the old tags and old plug-ins to play media. My HTML solution below is just one idea for cross-browser support that offers you the best chance at a true HTML solution to the complexity of playing video on multiple platforms in multiple browsers and versions. You still will likely encounter issues. Keep in mind the list of problems and complexities you must address to get close to 100% support in legacy browsers is often beyond your control, independent of HTML. It touches on many different issues in media playback and codec support in browsers, old and new. But multimedia playback in web pages has gotten much better with the new HTML5 standard, since playback in HTML5 is now independent of plugins and downloadable players. Before I show you my coded solution, a couple of issues that still might block support in your browser tests are listed below:
Codecs | IE | Firefox | Safari | Chrome | Opera | iPhone | Android |
---|---|---|---|---|---|---|---|
.ogg | none | 3.5+ | none | 4.0+ | 11.5+ | none | none |
.mp4 | 9.0+ | 35.0+ | 3.2+ | 4.0+ | 25+ | 3.2+ | 4.4+ |
.webm | none | 4.0+ | 12.1+ | 6.0+ | 11.5+ | 12.2+ | 2.3+ |
.mov | plugin | plugin | plugin | plugin | plugin | plugin | plugin |
.wmv | plugin | plugin | plugin | plugin | plugin | plugin | plugin |
.flv | plugin | plugin | plugin | plugin | plugin | plugin | plugin |
.swf | plugin | plugin | plugin | plugin | plugin | plugin | plugin |
.mpeg | plugin | plugin | plugin | plugin | plugin | plugin | plugin |
.avi | plugin | plugin | plugin | plugin | plugin | plugin | plugin |
.rm | plugin | plugin | plugin | plugin | plugin | plugin | plugin |
Ok, Show me the Cross-Browser HTML Video Solution! I will! Now that we have the "nasty" stuff out of the way, let's see what we can do to code a nice cross-browser HTML5 tag set to support a variety of old and new browsers. Instead of describing what the code does, just review the HTML architecture below and test the code with your own videos and with your own legacy browser testing strategies. The goal in this strategy again, is to support a wide range of old and new browser in a simple HTML solution you can cut-and-paste. My solution below combines three (3) different media "fallback" elements that support the following browsers and playback strategies:
The code and sample video demo below has all the code you need to get started. This solution should work in a wide range of old and new browsers. Just paste in your own video file paths and media type values. Change the dimensions in the CSS inline styles, if you like. That's it! In the test below I am using 3 fallback video codecs of the same video to increase support across all browser types and versions: "MP4", "OGG", and "WMV". There may be minor issues in how some very old browser interpret various media types with non-support in some cases. The 'video' element below will first try to play the first two media types in HTML5 browsers. The 'object' and 'embed' elements contain an older "wmv" version of the video for Windows Media Player in older browsers on Windows computers as a fallback. You could enhance this "playback strategy" further by adding Apple's Quicktime ".mov" file to this list for people on Mac's. And if you really wanted to support 2000-2010 browsers, you could encode a Flash Video file and hope those older browsers still use the old Adobe Flash player. If you really truly care about 99.9% of video playback support, these types of strategies (plus my code) will get you there! Just do not get mired in the "latest and greatest" video encoding techniques online, or some open source coding tricks some kid online in web articles try and tell you work great, because they look good on their new laptops. Often what works for these developers fails miserably in numerous edge cases. What works best is honoring and working with a wide range of browsers, codecs, and users online, then implementing a testing strategy in these newer and older browsers to see what actually works.
Just remember one thing: This new 'video' element in HTML5 is for HTML5 browsers and media only. The 'object' and 'embed' elements are there for everything else that won't play in these shiny new browsers, which includes all other browsers around the world going back 20+ years that still trigger calls to newer, or versioned, or long dead players and plugins when trying to play your videos. You may still deliver generic error messages to their browsers inside the video if none of the media types or video codec's below are supported by their specific browser or their type of device. Therefore, realize that this solution isn't going to solve all your video-viewing needs, just enhance your HTML markup so it supports as many new and old browsers as possible. That strategy will make your HTML website superior to anything anyone else is building inline over time with less complaints or bugs or issues compared to the developers stuck supporting a tiny range of the newest browsers and users out there.
In HTML5 and CSS3, the new "grid" system now allows you to build website layout pages without having to use the older systems we used to use. This also includes its sister CSS layout tool "flex", which is new in 2017. The rule is use "grid" for larger layout systems and "flex" for smaller modular layouts within the page. Use both system when you want something beyond either static positioned layouts or which must replace "floating" block layouts that might have gotten too complex or inflexible. Keep in mind, CSS using simple floats and positioned elements still work best when you need them. In general, only use "grid" and "flex" when you need something that not only must adjust itself to the changing content inside it, but adjust itself to the subtle shifts that occur in devices like tablets or rotating monitors that change viewport space quickly and which need to move content boxes around to maximize their display. Note that "grid" and "flex" both use an HTML "parent-child" model with a container element that defines global characteristics and child elements which fill them. Both also use x-y axis lines or a bi-directional, 2-D layout structure to manage their flow of boxes within the larger container box.
In the old days (2001), we developed powerful "negative margin layouts", positioned, and cross-browser floated "divs" to carefully construct cross-browser, flexible page layout pages. We built some really powerful positioned layouts that filled the viewport with a nice header, footer, and content panel. Using special negative margins we even got these to work well in broken box-model browsers like Internet Explorer 5.5 and 6! These designs could be fragile, however, and relied on a number of CSS hacks and tricks that risked breaking should someone untrained in CSS fail to implement them correctly.
These older CSS page layout designs still work well today in web pages around the world and likely will for some time to come. I was even thinking of posting one in this tutorial. But then I realized, many new developers routinely reject older web designs in favor of JavaScripted solutions that don't require any direct knowledge or control over CSS and HTML. Some assume the latest and greatest will save them. Systems like Bootstrap or heavily JavaScripted Modernizr have created the illusion that their systems will always solve all your problems. Failing to learn CSS or understand how HTML layouts work has simply piled more code into our browsers to solve what used to be very simple layout problems using a tiny bit of code. Because I do not want to force something old that forces people to layer over them with more scripted solutions, in 2022 I have decided to take the middle-road and simply embrace HTML5 grids, and help you learn how to use them and their CSS in your web pages. You will feel more powerful knowing you do not need Bootstrap or Modernizr or JQuery to create a simple page layout. Besides, with "grids" and HTML5 finally starting to dominate the web development world, after 15 long years of using floats, I too have decided it is time to make the big leap towards grids!
Using the new CSS grid system, we now have a new layout web page tool we can use with moderate support in a few older browsers. For example, even Internet Explorer 10-11 partially supports HTML5 grids using limited, proprietary, prefixed CSS properties (more on that later). But it appears in 2022 there is finally enough browser support in all major browsers to begin using grids. If you use a "progressive" CSS system, like my Universal CSS Framework, you wont be styling for browsers like Internet Explorer 1-7, anyway. Internet Explorer versions 8-11 would be your only holdup in using CSS3 grids in most cases. That means, IE 8 and 9 are the only real browsers left that need a layout alternative. IE9 supports HTML5 elements, but not grids, while IE8 support neither. It still may be important you deliver progressively degraded, non-grid, or float alternatives for these last troublesome browsers. But it's no longer a requirement using new "progressive" CSS designs that degrade HTML and CSS gracefully with limited layouts in older browsers like IE 1-9. Since most of these older browsers are rarely used now, we can provide a few with some simulated grid abilities, while giving others more block-level stacked content designs. Going forward we are then free to provide the newest browsers with full HTML5 grid solutions. In the last part of this article, I will touch on some of these cross-browser issues with full sets of sample code you can drop in your web projects that is fully supported in many of these browsers.
Before we get started, let's talk about various aspects of grids.
The grid is first defined by a concept called the "grid line". Grid lines cut across the width and height of a grid and separate columns and rows from each other. Grid lines start and end before and after the first and last columns and rows in your grid. And that starts the confusion. For starters, the columns and rows that hold content are often called "tracks". A grid track is the space between two grid lines. Around those tracks, grid lines start with the number "1", to the left of a column track or above the row track, and then numerically count forward as each line is added. Every column and row track starts with "1", but grid lines represents the line "before" the column or row itself. It doesn't represent the actual column or row number. So, if you later tell a column to span a range from line "1" to "2" it represents the bounded grid lines around tracks and will ONLY create one column. Why? Notice the 2nd grid line starts AFTER the first column's box. So, you are saying create one column, not two. Telling a grid to span two columns means you need to say, go from line "1" to line "3". See the visual below. Again, this is not intuitive, and one of the many confusing aspects of grid design, to me. Whoever designed CSS3 grids obviously made things harder for everyone. But now you know.
In CSS3 grid systems, it is also not intuitive how a grid is designed or populated. Grid layouts on the surface excel at dividing a page and its content into major regions, but how that is actually implemented takes some practice. Like tables, grid layout enables an author to align elements into a giant rectangular block of columns and rows in a grid layout divided by lines like streets in a city. To create a grid, you will need both HTML and CSS. To get started, you first create a single HTML "div" element or container element to hold what are called child "divs" or "grid items". These children will be the cells that hold content in the grid. But this outer "div" is the parent grid element, and defines your grid by setting its "display:grid" property in CSS. This property can also be defined as "display:inline-grid" for more flexible layout placement that fits in with horizontal text content rather than vertical.
In addition to the CSS "display:grid" property on the parent "div", you can also set the "grid-gap" property which defines the spacing between grid rows and columns. It works just like in an HTML table spacing setting. If you add background color to grid with gap spaces, its color shines through the gap. An example of using gaps might be "grid-gap: 2px 2px", which would tell a grid to create spaces between rows then columns with 2 pixels of space between each. "grid-gap: 1em 1em" is another version of adding gaps using text units. Using "em" or "rem" units as opposed to pixels is an ideal way to separate text or content blocks which will enlarge or shrink relative to the font-size set by the end-user in the browser. Pixels are static and ignore user settings, unlike "em" or relative font-size units, so I always use "em" units in my grids, instead. Even though "gaps" are helpful, I recommend you not use the grid gap properties as they are not supported by IE 10-11 and add extra dimensions to your grids you do not need. A better alternative is simply to use CSS padding inside your cells to separate content from neighboring cells. Below, I will still show some examples using gaps so you can see how they look and work.
Beside a display value of "grid", a parent "div" also needs a "template" which determines the initial layout design of the grid. These template properties decide the initial numbers of rows allowed vertically and their height, and the number of columns horizontally and their width in the grid. This determines how "grid item" children that will populate the grid, and is considered an explicit grid setting. Because web browsers are always limited more by available width in the viewport (height can be scrolled), grids like everything else in the web world, rely on these critical "column" width and count settings. If you leave this "template" CSS property off the parent grid, the grid will by default have one column per row and its children stack like normal HTML blocks. So be sure to always define at least one template property for your rows and/or columns. A template example for columns is as follows: grid-template-columns: 10em 10em auto. This says to always allow room in your grid for at least 3 columns horizontally, 2 at a specific "em" or width of 10 character widths max, with the third column allowed to be a flexible cell stretched to fill the rest of the available width. Besides "em" units, you could use the new "rem" unit. It means to take the root element's font-size rather than the inherited parent's size. In both cases, the font-size is based on the chosen 'font-face' and is equal to the space of one "em dash" character for the given font in width. The last unit "auto" in CSS usually means fill the available space, don't overflow it, but use an amount no smaller than the given content. So, using "auto" in this case would mean this last column in our template would stretch to fill the remaining width of your grid but remain no smaller that the content it holds when collapsed.
Lastly, each of our child "divs" is considered by the parent "div" grid to be a "grid item", as we mentioned above. These grid children are the cells that will fill our rows and columns in a grid. These cells are simple styled "div" elements, so have some backwards compatibility with older browsers who all know "div" elements. You can add as many of these grid items as you like, keeping in mind how and where they might populate the columns and rows you defined in the parent grid element. In this example below, we have not defined rows yet. So the grid auto-populated those for us. As you add more and more of these "grid items" inside your parent, they will fill the grid columns up horizontally first in your grid's first row by default, then drop down to the next row, filling each row like this with new grid items in columns as they go. I have created a sample grid below in HTML with the information discussed above so you can start to see how the HTML is designed. Note: I have added extra CSS styling to make our grid look presentable.
Keep in mind, if your grid item count does not finish filling a row it will have an empty place where cells should go and remain as an unfinished row. These "explicit" grids do not try and complete rows or columns unless you provide rules that allow them to fill them out in a predictable way (more on that later), or explicitly tell them as we have done in these early examples. This makes HTML5 grids very different than say the "grid" of an HTML table. I thought logically a grid would be a set of cells and blocks that fill a rectangle by default. But these "grid items" actually fill a grid more like a flowing set of floated blocks, much like our old floating layout systems. You can tell a grid to populate its cells vertically by stacking columns in a limited row count design. But in this example above, we are using the default which is horizontal columns placement. In more advanced grid designs, you can tell specific blocks to fill specific columns and rows, even extend cells across columns and rows. But that will come later in this tutorial.
Below is another example of a grid using a few extra properties. This one has a set width using two columns in the final layout. This rigid design will push text content down the page as it grows but remains a rigid width. Note: As always, when it comes to grids or any CSS design, I like to use "em" text width and height relative units, as each display of your HTML and CSS will now grow based on the user's set font size on the device and browser, growing or shrinking to fit their viewport, font-size, and display preferences. This is always superior to pixels, which could expand or collapse to very small sizes based on the screen because of shifting "device pixel" ratios that change.
Many grid widths and height values on rows and columns can be set as "auto", which is the default, in most cases. Setting grid cell widths to "auto" tells a grid to collapse as small as possible when text allows but grow as big as possible, expanding the cell dimensions when needed without breaking out of its box. All CSS block-level elements work this way with "auto" dimensions. "Auto" is great for filling missing unknown widths in one column, for example, as content will not break out of the cell, but terrible when used to fill in unknown widths across multiple columns where space is shared. Why? The reason is simple. As soon as you add content to one "auto" width column the others collapse their widths to the smallest possible, as "auto" cells with content stretches to fill as much available space as it can find. Use "auto" dimensions that way if you don't care about collapsing column widths, but need a completely flexible layout grid. These cell dimensions can also be designed using hard-coded units, like pixels, and so use hard-coded values. But, I do not recommend it. Pixels are terrible solutions as most devices interpret pixels differently as far as screen width or height. With the new "device pixel" on HD screens you cannot rely on the amount of real estate a pixel-based column or row will fill in terms of physical real estate on a screen. As mentioned, I use "em" (use "rem" if ignoring older browser, IE 1-8). This way your units stretch based on the user's font size settings, not a hard-coded value.
But there is a better way to set dimensions on columns using the new "fractional" unit for grids. It solves these issues. The new 'fr' unit represents a "fraction" of the total available space in the grid width and assigns fractions of the total available width to each column based on the sum of all fractional units combined. Example: If there are 3 columns defined and each has "1fr" assigned to it, the total width is "3fr". Each gets one third of the total width of the grid dimension (1fr or 33%). If on the other hand there are 3 columns where "2fr" is assigned the first column and "1fr" to the other two, we have a total of "4fr" units assigned. The "2fr" unit assigned to the first column would fill 50% of the space (2 of 4 fr units), and the other two would get 25% each. The 4fr units assigned is the same as: 50% + 25% + 25% = 100% width used. Now, let's look at a new grid example using those 3 fractional units.
Quick Discussion: In the example above, we see the "2fr 1fr 1fr" layout at work. But what if the first of the three columns had a width of "100px" and "1fr" was assigned to each of the other two columns, the first column would always be 100px in width and the other two columns would get 100% of the width left over in total width after subtracting the first 100px column width. The two "fr" columns would EXPAND to fill the growing width in the grid. This works very much like "%". I like "%" to stop "auto" columns from collapsing with no content, which they will do. But I recommend you use "fr" instead for a flexible layout that will not collapse based on content, versus using "auto" or "%" or "pixel. Only use "auto" if you need a single "auto" or flexible column to fill in the rest of a grid layout, or multiple "auto" columns if you do not care that they collapse to various shared widths based as various content in your grid cells. Use "fr" for a percentage of the available width regardless of the content inside and to prevent collapse. Of course, if you shove a giant image into a "1fr" column that is a member of many template columns, then you COULD break your shared layout sizes. Always use "fr" fractionals if you can. They are even supported in IE10-11 grids. Otherwise, if you think you could have content of unknown dimensions added to your grid columns, then use "auto".
In the grid parent properties you can also use the "grid-template-rows" property to control how rows perform in your grid. Each value in the property represents a "row height" as columns represent width, with each item you add to the property representing one new row. Example, "grid-template-rows: 200px 100px" means two rows with the first row set to "200px" in height and the second row set to 100px. When you set explicit rows like this, no additional rows are supported or will be created. But if there are columns that overflow past your rows, all rows added because of the overflow collapse to "auto" for width and height. For this reason, if you use the "grid-template", "grid-template-columns", or "grid-template-rows" properties, remember you are using the EXPLICIT grid, not the implicit grid where the grid only has the rows and columns you define initially. There is some limited freedom with the grid object when adding more columns and rows like this using "template", if your "grid items" list grows or content changes. But if your grid items exceed the rows and columns needed in these explicit grids, you will see unexpected results. That is important, and is one of the things I do NOT like about CSS3/HTMN5 grids. They just were not thought through well enough in their design to be consistent and intuitive.
But these kookier, more explicit grid systems do have fallback that kinda makes sense. Most grids do not know how many rows your multiple child "divs" or cells will fill so they have to either follow a rule you set or assume something else to hold the growing grid items list. How "grid-template-rows" is used to populate rows is still based on the number of grid items or "divs" you create. In the explicit grid, you must try and tell the grid how many rows or columns you need based on your grid item count. It really depends on how many cells you add, right? It could be a few or a few thousand! But setting only one or two row's height and not knowing how many rows you end up with or explicit grid items you may have means there is something inconsistent here with this property in how it must handle this contingency. For that reason, I recommend you NOT use "grid-template-rows" or set a row count or height. Just let your grids collapse to fill an "auto" row height as content grows, and let row count be implicit. Unless you know your EXACT grid item count or have a limited grid pattern you will use, its best to not use these template row properties at all.
Content is almost always flexible and not fully known in web designs. If you are designing a static or rigid grid system and do know your row counts and final grid dimensions based on the number of child "divs" or cell count you added, then assuming you want say 3 rows max, you could add the following to your parent grid: "grid-template-rows: 5rem auto 5rem". This creates a grid with set top and bottom row heights but a middle row that fills the available page height as needed for growing textual content that fills the available height of the page. In this design, content in the middle section can safely expand vertically as content fills it. These heights on rows that have a hard-coded value like "5rem" or "100px" have one other nasty feature. If you have content in a cell that goes beyond its fixed dimensions (either height or width), there is a NASTY cell content overflow that happens where your text or image overflows its cell and spills into the next grid row or into the grid itself! You then have to add "overflow: scroll" or some other features to either hide or show the text that overflows the grid cell using scrollbars. Quite a nasty design! That is why, if you use the "grid-template-rows" feature, remember that adding "auto" here is your best friend as it will always expand to hold the content! By the way, if you added a 4th row value in your template after these first 3 rows, and there were no cells grid items to fill it, an empty row would still get created with no columns cells. This is why again, hard-coded row or column layouts and explicit grid systems depend on fixed grid item counts and known grid item content before you begin any grid designs.
Let's now demonstrate one good use of the "grid-template-rows" explicit grid feature, anyway. One example of this type of row design might be a Header-Content-Footer web page layout design that needs a flexible content middle but with static header and footers. In that case, using "grid-template-rows: 10rem auto 10rem" format might be ideal in limiting your layout to three rows with a head and a footer, but using a stretchable middle row (main) set to "auto" row height. An example of a simple page layout grid with set grid items and row counts with spacing is shown below. Note the use of the "grid-template-columns" and "grid-template-rows" combined to set columns and row structures, plus new CSS styles on your grid items which controls how many columns it spans using the new "grid-row-start" and "grid-row-end" styles on the header and footer. I will let you look at these new rules in the HTML below to see how it works. Note: I am using "rem" units here instead. Because IE 1-8 does not support "rem" units but also does not support "grids", those browsers in this case would not use these CSS value settings anyway.
As mentioned, when using explicit grid settings, if you set a hard-coded height or width on a row or column, and if your content needs more space, content will overflow its cell and break through the column or row by default! Bad idea! If that's your design you can add "overflow:auto" (as I have done above) to child cells which will create a scroll bar on the cell or on the parent grid if content flows through. Just remember, the "template" settings on the parent grid control basic grid track dimensions, initially, but your cells control the final space they need. Planning for cells and their "unknown" content is therefore very important. Always plan for content to grow. That is why your grid settings need to be as flexible as possible. Only outline a "starting layout" for your grid, with accommodations for when and how its content can break. Otherwise, your viewers later may be in for a surprise!
Advanced Grid Features: Other than the "template" grid properties, everything else you add to a grid defines the 'explicit' grid, or what is actually filled into your initial layout. You have more fine-grained control over each cell, padding, border, and color. It is just a matter of what styles you apply. But there are other features of grids you cannot control. At first, you would assume a parent controls the grid layout of columns and rows. But as you will see in the samples below, that is not the case. It's important to understand that both the parent and child elements with their own styles and content work together in union with the parent to define the FINAL grid layout you will see on your web page. Using the "fr" units or "auto", and avoiding defining specific row heights initially, can help in starting out flexible and fluid as your grid grows to hold all kinds of HTML "stuff" you did not expect! As we will see below, however, there are many combinations of CSS settings that can alter grids or even distort grid columns and rows. So, if you learn anything about "grids" from me, remember this one rule: Grids can be changed by content and styles despite your carefully designed, grid settings! Most people on the Internet will not teach you that!
You can add as many child "div" elements as you like inside the parent grid "div". But each cell can also have its own "item properties". As you add them, assuming you set your "grid-template-columns" property on the parent and don't add "grid" styles to these children, those "div" cells will stack first visually across the grid, horizontally filling the column in a row, then drop down, creating new rows as you add more cells. This may create some rows with missing columns, as you might not expect. That means the grid honors the column count horizontally over row counts expected. Again, this is another reason why in grids, it's not a good idea to try and anticipate row counts or row heights unless you have a strict layout with known content and child cells added. As mentioned, if you know the exact number of child "divs" you are adding in say a header-content-footer design, then yes you can safely define row heights and row numbers. Just remember, grids have to be flexible to deal with those times when you add some unknown cell count. And so grids manage that by creating partially filled rows of cells as more are added to the parent.
Grid "Weirdness": As we mentioned, the parent 'div' generally defines the column limit, horizontally, not the row limit vertically, so that child elements can flexibly fill the row count set, as needed. But what if a child "div" decides it wants to extend across the columns in a row and go beyond say our 3 column layouts shown above? It turns out you can tell child 'divs' to extend beyond the parent's "grid-template-columns" property or defined column limit and create even MORE columns, breaking the horizontal design of the grid! In that case the grid's child cells can redefine a grid and go beyond its defined limit shown above in our 3 column grids and create 4 or more columns! The result of this change now has affected our elegant, evenly spaced "1fr 1fr 1fr" grid shown in the example below. It now adds a fourth column with an "auto" width default that has collapsed. This shows that you can not only ALTER a grid's design using its children, but change how default layouts act using child "grid item" properties by increasing rows, by adding more children, or by expand columns horizontally.
All these examples were added to warn you about grids and the unexpected "possibilities" in grids you might not expect or accept that can happen if you do not design them carefully with deep knowledge of your web page's expected content, changes, and designs. Note: Below, I have added a new grid item property to the first cell: "grid-column: 1 / 5" to break this grid. This property is shorthand for the "grid-column-start" and "grid-column-end" properties. This value "1 / 5" says to start this cell at the first grid line and "span" it or end its width on the 5th grid line, basically saying to stretch the 1st column to 4 columns. This example shows how a single cell can break through a parent grid's column and row settings and redefine a new grid layout!
Up until now we talked about more rigid and "explicit" grid designs with some weird things that can happen if your grid elements break out of or try and extend themselves beyond the parent's rigid assumed layouts. There are more flexible rules you can apply to "implicit" grids that let the grid figure out how to populate a grid in a more flexible way. This allows support of small screen devices like mobile phones, as well, which must adapt to changing widths with new layout rules. These "grid concepts" were new to me until I did more research, as the IDE's I use to write web pages did not support many of these features, nor was there decent examples on the Internet to help me. So, I hope these help you.
For most of the examples below we will use the new CSS shorthand property called "grid". We are going to use some more advanced grid values with it below. All of the cells (or child "divs") below have no special grid properties applied. The parent "grid" property controls its design, as shown above each example, using more flexible grid properties.
Below, is our typical rigid design. But this one uses the new "grid" shorthand CSS property. Here, we explicitly tell the grid we want two "auto" height sized rows filled with 5 cells all equal width. This is the old way of assigning this property as its rigid and doesn't allow the grid flexibility to decide how to populate rows and columns with the 10 grid items or child "divs" it holds. Note: Using "auto" prevents cells from overflowing their boxes and spilling into the next row. You will see that feature below with cell number 2 and its extra content.
<div style="grid: auto auto / 1fr 1fr 1fr 1fr 1fr;">
Let's try a better way! In the example below, now use more advanced grid language that tells the grid how and when to populate its limited grid items. The new "grid: property defines rules for grids that apply to separate row and column properties ("rows / columns"). The left of the "/" applies to rows only, to the right controls columns only.
In the example below, we now apply some new values to our CSS grid property. The first is the new "auto-flow" value. "auto-flow" is the most powerful "grid" value in flexible grid design. It controls how the algorithm for auto-placement of grid items works, specifying exactly how auto-placed items get flowed into the grid, either by rows horizontally or by columns vertically. This new rule in the example below tells the grid to take all the blocks and populate the grid horizontally in the first row. It also tells the grid to create as many rows as needed based on all the grid items available, taking each item and stacking them in order across the row horizontally until it is filled, then dropping down and creating a new row. This is different than setting explicit rows, as in earlier grid examples. "auto-flow" for columns works the same way, except instead of honoring rows it stacks items in he first column vertically first across all rows until each row is filled. Then they start a new column in the first row again. "auto-flow" can also have a value after it, like "auto-flow 100px" which would limit its height on every row created. But this is usually not a good idea as any content greater than the cells height allowed would overflow into either neighboring cells or into the bottom of the grid container. As mentioned, I usually add the "overflow:auto" CSS property to my grid container to prevent that. It will create scrollbars if needed on the grid to contain but show content in cells, which is better than hiding content. The "auto-flow" generally adds a default height of "auto" to rows and "auto" to width in columns so they will not break out of their cells. So understand that grids are designed to expand and grow as needed to hold content. This is more true of rows than columns when "auto" or "auto-flow" is used.
Important: You CANNOT set "auto-flow" on both rows and columns. Why? The grid does not know if you meant to add a column or a row for that extra cell, so is conflicted! Will see an example of all this below.
Next in the example below, lets look at the CSS grid container rule: "grid: autoflow/repeat(2, minmax(300px, 1fr))". This says to repeat columns as needed across rows as defined by "auto-flow" in the first section. This means use "auto-flow" to build dynamic rows as needed, then columns should start stacking horizontally, filling out rows in units until full, then creating new rows. Using "repeat(a,b)", the "a" section represents how many repeating items maximum to create. In this case it would be columns. The "2" means always create two columns max. You can also use "auto-fit", which would mean to use as many columns as possible. This would add flexibility to your grid, allowing the grid to decide, but would mean some rows are not filled with cells (remember we have 10 grid items in these examples). The "b" section of "repeat" sets the dimensions or our grid items, or in this case the "width" of columns in the rows. Many use a set width on pixels or em units, but we can use a new feature called "minmax" which allows you to set the minimum width a column should start at, then its maximum width it would allow. The same rule can be applied to rows, if needed. This can be in "pixels", "percent", "em", etc.. In the example below, we use a special "fr" or fractional unit. Thus, "minmax(300px, 1fr)" value says to start each column at 300px minimum width then grow it as large as needed to fill the space available, making sure each column in the row are equal or 1 fractional division of the total space divided among them. Cool, huh? This gives our grid the ability to grow as needed as content in our grid items changes, yet limited by the number of columns we set, which is 2. Again, this column limit is usually based on the number of "div" or child grid items we have. If we had 12 we could use odd or even numbers of column, for example, or our "auto-fit" feature. You will see that in an example after this one.
<div style="grid: auto-flow / repeat(2, minmax(300px, 1fr));">
The example below is the same as the one above, but in the column settings for "grid" in CSS we are using the new "auto-fit" value rather than a set "2" columns. "auto-fit" tells the grid to populate as many rows with as many columns as it needs, ignoring any set column or row counts. This means as the browser window narrows in size your column counts collapse and rows increase to fit the viewport. This is great for mobile phone web designs! Note: This will often create rows with empty cells if the number of grid items cannot be divided into odd or even numbers. Instead you can use a grid item count of child "divs" that is divisible by odd and even numbers like 6, 12, etc. so no matter how many columns small screens create it always fills each row with columns. I am using "12" grid items to demo that feature, below. Narrow your browser window and watch how the grid columns collapse gracefully to fit the width of the screen. Because "12" grid items can be divided up into rows of 2 or 3, its grid items will always fill a perfect square grid of some type. This is the most flexible of our grid designs using the new advanced flexible grid units! "auto-fit" also has the great ability to drop down multiple column layouts into fewer columns in the grid supporting mobile phone designs and narrow tablet screens. This means you do not need media query to control this feature. Its automatic! The other feature of "auto-fit" we you will see is the following: If your grid has extra rows or columns left over, it removes them completely, essentially setting their dimensions to zero.
<div style="grid: auto-flow / repeat(auto-fit, minmax(300px, 1fr));">
Below, I'm demonstrating a few more values for "grid" you can use. Here I am using set height on the first row (100px) with repeating ones after it set to 4 rows total. Notice we are still are using a set number of rows. In fact we are saying, "start with a single 100px row, then add new ones in batches of 3 all the same height". The first row has a set height of 100px, but the repeating ones share the same heights. This row count of "4" total is critical in holding all the grid items in columns. For columns, I am now using the rule, "/auto-flow 1fr" in the column section. This now tells the grid to take all the grid items and start populating the first columns across all 4 rows first, adding items in each row of the first column until filled, then start the second column on the next row. "1fr" means to let columns stretch and share the available width of each row as needed. Again, an implicit, more flexible design is used here. Note: A black space remains in this example. Thats intentional. Notice, I am using "4" rows, though I have "10" grid items. There are not enough grid items to populate these missing spaces. This shows how partial rows of items can be left empty. This might still be ideal for displaying photos where you don't know how many will fill the screen (the count is variable) but you need them to stack as closely as possible to fill the space available, creating new columns.Its important you see how grids here do not stretch columns to compensate in this design, but fill down into all 4 rows, first.
<div style="grid: 100px repeat(3, 1fr) / auto-flow 1fr;">
In this grid example, I want to show you how grids can try and interpret your assumptions as best it can, but can also fail. Notice the empty space in the example below. You have told the grid you want one row with 100px height, but then one column with 200px width. There is a contradiction here. The grid cant determine if you want more than one column or row as you have 10 grid items, so it chose 10 rows, instead. Because columns are only allowed to fill 200px widths, but must honor the row first, there is empty column space left over that it cannot fill.
<div style="grid: 100px / 200px;">
Now I have added "auto-fit" to the row design in the same design above. The grid is still confused as to how many rows and columns to add. It's told to add a single 100px height rows but also must set a single 200px column. Adding "auto-fit" is a new feature. It says to fit everything in the grid but remove any extra space, rows, or columns that refuse to fill the grid. I could have added "auto-fit" to the column side of the property value and it would work the same in removing extra grid space and forcing all rows and columns to be filled DESPITE the base pixel settings I applied. Again, as above, the row rule is honored first in cases like this where it does not know whether to add extra rows or columns to hold all the grid item "divs". In this case, it still fills rows to hold the grid items vertically. But now, using "auto-fit", its erased any extra rows or row space not needed. I like "auto-fit" because it cleans up the mess we create!
<div style="grid: auto-fit 100px / 200px;">
Now for something completely different! Another cool grid property value I like is "fit-content()". Like "minmax()", new "fit-content(max)" allows you to set a max width on a column similar to "minmax(max-content, max(min-content, argument))", but where the minimum width is always the maximum available space, and where max is never greater than the maximum argument value. Since the max must be a value (not fr, max-content, etc), "fit-content(max)" works best if you want a cell to always fill available space up to a hard-coded max unit value. (Note: "fit-content" can be used with other CSS properties, like "width: fit-content" in CSS3 supporting browsers)
Typically, most grids default to a width of "auto", which is a non-collapsing minimum default dimension in grid rows and columns. With "auto", content starts as a minimum value needed to hold content, but grows as needed, never breaking out of a column or row. "auto" is essentially the same as "minmax(min-content, max-content)" but using the minimum space. This default "auto" basically says start with the smallest dimension needed to hold available cell content. The problem with "auto" in grids is it always starts out cells with small dimensions, first. With multiple columns of text these "auto" cells often collapse even smaller, giving terribly small cell dimensions until their increasing content fills more and more space, expanding the shared cell space. "fr" or fractionals now improve that default space but shared width is not predictable. Dimensions like column width are even more unpredictable using "auto" if you are using a fluid design. To solve that, you can use "minmax()" as a way to contain columns width using minimum and maximum in a range that helps. But your columns often start with minimum dimensions that explode into maximums that you might still want reduced in certain situations.
With "fit-content()", the cell's width stretches with the text content to fill the full "available size" of a cell, but allowing content in a cell to use more space up to a maximum width. "fit-content()" is essentially "fit-content(stretch)", but expressed below as "fit-content(maximum)". Unlike "minmax()", this max value must be a set unit value, not "fr" or other implied value. So, your cell must stop at some hard unit width value. For this reason, the "fit-content" design seems to work best where you have one or more "fit-content" flexible boxes with a "1fr" cell that will fill in the extra space. The example below demonstrates this feature with "em" unit maximums, which I prefer. "em" is a universally accepted font-unit that matches the relative font-size set by the user's browser. Notice, if we had used "auto" or "minmax" instead of "fit-content", the first cell would have likely collapsed to the smallest word in the cell rather than start to expand towards its max value as text is added.
Note: IE1-11 does not support "fit-content". Instead, you can kinda simulate this feature on column widths using "minmax()" or "auto" combined with "fr" units. Note: Multiple cells may still expand much larger or collapse based on text size, however.
<div style="grid-template-columns: fit-content(10em) fit-content(20em) 1fr;">
A Note on "justify-content" and "align-content: If for some reason you create a grid parent with columns, but you use hard-coded values so that the width of the columns is less than the total width of the parent, but you still want those columns centered and spaced, you can use the 'justify-content' to align the "floating" cells inside horizontally and "align-content" to align the content vertically inside the grid parent block. This ONLY works if the container is larger than the total width of all the cells combined in a row (example: "grid-template-columns: 20rem 20rem 20rem"). The sample grid below has settings you can use in that case to center all the columns in a row automatically and equalize the spacing between their cells. Normally, the default is what you want for both these properties using grids, which is "justify-content:normal" the same as "justify-content:stretch", and "align-content" the same as "align-content:stretch". "stretch" means to distribute all items evenly with items "auto" sized to fill the container. There are more properties and more values you can use, many of which bleed over into "flex" properties (an alternative to "grid"). But for now, consider using the default grids created below with these defaults to get you started.
Customizing Grids The Right Way: In this last section on grids I will touch on some minor customizations that make managing grids much easier. You can Google these ideas online, but I'm going to just add a few new CSS properties below to fine tune my last grid examples, so you start out on the right foot with a nice reliable template. I have tested these example, so they will work well in many website layouts.
There are so many ways to use grid properties. Its overwhelming to me, too. But I thought I would list most of the major combinations below to help you. The "grid" CSS properties below are all shorthand properties that set all of the explicit and implicit grid properties in a single declaration. Often you may still combine them. For example, all of the "template" properties work best when used as separate properties. Or, you can simply use the shorthands to do everything, like "grid-template:" or "grid:". There are too many variations to list, but below I have outlined most of the various "grid" shorthands combinations you can use and what each feature of the grid they control.
The "grid-area", "grid-row", and "grid-column" affect only the "grid items", not the overall rows and columns of the larger "grid container". So, set those only if you prefer to control the grid item-by-item, which I do not recommend. The [values] for rows or columns below can be, "fr", "px", "%", "auto", "auto-flow", "minmax(min, max)", or "repeat([count or "autofit"],[values])". Notice below that the more detailed shorthands get stacked progressively down into the larger ones below. If think of it that way, you will see that the first shorthand properties are just reused in the later ones. So, as you go down the list you will see the items defined at the top of the list can be fitted into the larger shorthand items below:
(Use these for GRID ITEMS only) grid-area: [grid-row-start] / [grid-column-start] / ["span"] [grid-row-end] / ["span"][grid-column-end] | [area name] grid-row: [grid-row-start] / [grid-row-start] grid-column: [grid-column-start] / [grid-column-start] (Use these for GRID areas, rows, and columns) grid-template-areas: none; grid-template-rows: none; grid-template-columns: none; grid-template-areas: "area1 area2 area3"; (one phrase per row) grid-template-rows: [values]; grid-template-columns: [values]; grid-auto-rows: [auto size of each row]; grid-auto-columns: [auto size of each column]; (Use these for GRID shorthands for combined areas, rows, and columns) grid-template: none grid-template: [grid-template-rows] / [grid-template-columns] grid-template: [grid-template-areas] grid-template: [grid-template-areas] [grid-template-rows] grid-template: [grid-template-areas] [grid-template-rows / grid-template-column] (Use these for GRID shorthands for combined templates, areas, rows, and columns, plus "auto-flow") grid: none grid: [grid-template] grid: [grid-template-rows] / [auto-flow] [grid-auto-columns] grid: [auto-flow] [grid-auto-rows] / [grid-template-columns]
Alert: Browser Support for Grids in Internet Explorer is still very Limited! Internet Explorer versions 1-9 will NOT support 'display:grid' and instead will display your grid in vertical blocks of stacked content. IE 10-11 will only support grids with special pre-fixed "-ms" styles (see below) that support a small subset of what the full-featured modern grids in CSS support. That means if you use grids, plan for limited IE support (often version 10 and 11 only) with some type of layout alternative for the others. In general, you should at least always stick with 'divs' for all your grid children so older IE browsers by default will return them to block-level stacked elements of content that is readable, should grids fail. Because I want full semantic HTML5 used in my grids, I have chosen to use the HTML5 structural elements anyway, like 'header', 'main', 'footer', etc. I also like to use CSS "fallback" properties in the grid to address IE-only styles - like hexadecimal colors for 'rgba' colors which IE 1-9 do not understand. or "em" alongside "rem" font style units, the later which IE 1-8 will not understand. If like me, you use a robust custom CSS style sheet system that hides styles from older browsers (like IE1-7, which mine does), and reduces them to plain white page content blocks, that then leaves you with only needing to support IE 8-11 when delivering a layout alternative to "grid" designs.
Below is my IE 10-11 only version of grid in CSS that you can add to your grid systems that works in many Internet Explorer browsers, but falls back to simpler designs when the grid is not supported. This one does not use the modern HTML5 structural tags ("main", "header", etc.), however. Note: It happens to work good in modern browsers like Edge, Firefox, and Chrome. But, I recommend you use my final grid version show below this one, instead. It incorporates code into a better cross-browser version, than the IE example below, using HTML5 elements plus hacks om CSS for IE. But the code below will allow you to see a simple example of how IE interprets grid CSS rules.
Below is an HTML Grid Example that has all the "goodies" you may need to create a robust grid system. I've added as many properties as possible to give you a solid prototype you can use that supports as many old and new browsers as possible with a grid. This universal grid design also fills the browser window, so your web page layout can fit into the grid and control the complete viewport of the browser. This HTML Grid example also uses a traditional "Page Layout" architecture but uses grid "area names" that match the new HTML5 structural elements ("header", "main", et.c) in the grid design. The named items in the template match area names in the children's elements, id's, and CSS selectors. This is a helpful design pattern that makes laying out a page and managing its CSS and HTML5 blocks simple and identifiable as far as what each cell block's role is in the page and grid.
Header
Alert! Your web browser does not fully support our modern layout grid system! Our website works best using one of the following modern browsers: Chrome, Firefox, Edge.
content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content content
* Copy the CSS and HTML in the box below, then paste it into your web page to start using this universal cross-browser grid!
As mentioned above, "grid" and "flex" are two types of HTML5 layout systems that are closely related and often cross-over in terms of their functions. Use "grid" for larger layouts and "flex" for smaller ones. But often, they do the same thing. That is why I think they were poorly designed. But if you use them, because of their "cross-browser" issues in so many older browsers, I recommend you use them sparingly, or at least design alternative fallback designs for older browsers. I will try and show you code that does all that in this example, the same as I did in the above one for "grid". Simply cut-and-paste my code below, It has all the "goodies" to get you started!
I will not go into too much discussion over the history or influences of "flex" as its too much to cover. But I will simply say that in my opinion, "flex" is just another "grid", but on a simpler scale. Where grids have much more granular control over every single row, column, and cell (like in a table), flex is more about control over boxes that float and stack along a single dimension based on available width or height. For that reason, flex boxes feel like more of a replacement for "floats" in CSS and HTML, which worked fine and can still be used (see my float article in this page). Floats still have huge support in ALL BROWSERS, old and new, going back over 20 years now. The point of using "flex" rather than "floats" is you now have more granular control over how a series of boxes grow and shrink to fill a space relative to each other. With floats you only had limited control of box sizes. You also don't have to worry about floated items overflowing their container or the page flow. But "flex" boxes and layouts are really only needed if you have parts of a page that need to expand or contract critical content. It usually means some need beyond "sexy web pages" that affect larger concerns, like how information is maximized. Imagine, for example, a person with a large tablet they carry around all day, working in an industry like cars, buildings, or planes, or order tracking, or inventory.....where parts of instructions, forms, or design in the viewport need to be expanded as these large tablets used by people are rotated, zoomed, or expanded hundreds of times a day to view critical information. You will then see where these types of "flex" layout changes really turn a traditional HTML website you might see on a desktop computer into more of a critical, highly "flexible" application used by thousands of people that rely on those pages to do their job. That is where this new technology may shine in the future if browser support solidifies.
Just like with "grid", browser support of HTML5 and CSS3 features like "flex" are poor. It's only in recent years that support has increased enough in modern HTML5 browsers that flex can be used. The problem is, in the past decade there have been too many half-baked implementations of flex that have changed and so leave behind remnants of code that has changed several times! What is worse is support in Internet Explorer for flex is still poor.
Because my "grid" article uses features very similar to "flex" boxes (and was so exhaustive), I feel like I need to give you guys a break and shorten this "flex" tutorial quite a bit. Instead of showing you all the flaws and the pieces that break in this new "flex" system, I am going to simply list the basic design of a few "flex" layouts I recommend with code samples and solutions you can copy as needed. Now, I'll cover the basics of "flex" designs and the CSS properties that control them.
DON'T WORRY! If you couldn't follow all that listed above, I have "cut-and-paste code" below you can use, that has the most common property settings used.
This flex box example below should have all the code needed to give you MAXIMUM cross-browser flex support, including fixes to allow "flex" to work in Internet Explorer 10-11, which is "buggy", and a range of partially implemented flex solutions that changed in browsers over the past decade. Using the CSS and HTML below will guarantee fixes in many of these outdated browsers. It also allows IE 1-9 which does not support "flex" to at least fall back to a simple stacked content box set, which is better than trying to apply JavaScripted polyfills or other floated "hacks".
This sample code below shows a simple 3-box content design you can customize. If you are able to reduce your browser's viewport size, you will see how the middle box expands faster than the two outer boxes. When the browser gets small enough, the far right flex item drops down and fills the row beneath the other two, expanding to full width (I explain this in detail below).
This is the real power of "flex" - its ability to naturally adjust its box sizes to all kinds of viewport conditions as well as apply matching heights with little if any need for media queries or other complicated CSS code changes. It also handles the horizontal positioning and floating of boxes very well with minimal code in CSS and HTML. This also demonstrates how much simpler "flex" is from "grid" designs, which can get very complicated. So use "flex" for your simpler layout issues.
Flex container should generally have no style or color. The gray outer box was styled to show you how flex boxes fill the parent container. But I would remove that feature, unless needed.
Also in the code above, notice the wide array of "display" properties I added to the container "div" above. These are called web browser "prefixes" in CSS. This is used to address issues that remain with support in HTML5 browsers today and in the past that started to "partially" implement flex when it was still experimental. Because W3C recommendations were abandoned, that decision created a "mess" of broken standards and these unused prefixes and properties that current HTML5 browsers have either abandoned or still use. I recommend you add this extra "prefix" code into your CSS flex boxes, as I have done above, to make sure all the older HTML5 browsers understand flex going back 10-12 years. This is "bad sign" by browser vendors and shows how implementation of "display:flex" is still not fully supported in many modern browsers because they have refused to create an enforced standard much less follow one.
Notice how I have set the two outer child flex items above to use "flex: 2 0 auto" but the inner one uses "flex: 3 .5 auto". What "auto" says is, for the flex item's starting size, use the div's set width/height dimensions. What the first number says is for "flex-growth" allow the flex item box to grow twice or three times its size relative to the others when the width of the viewport window increases in the browser. The "second or middle number represents "flex-shrink". When "1" or "0" it means not to ever shrink the box from its initial size as the viewport shrinks in size. Because the "middle" or center box has a slightly higher starting width, plus its first flex value is slightly larger, or "3", than the other two, it will start out larger and grow bigger as the browser viewport grows. As it shrinks, though, I have set it to ".5", so it will collapse down to match the other two sizes. The result is the three items will grow to fill the flex container as the window grows, but the middle column with the most text content will grow faster. As the browser window gets smaller, all three will shrink back to their original size, the middle one down to half, until they cannot all three fit in the row or width of the screen. Because of "flex-flow: row wrap", the flex item to the far right will then break off first and drop down to another row as the window gets smaller. But it will expand to fill that row as its "2" or "flex-grow" value is set to grow larger. Another technique you can use is the following: Instead of setting "auto" values to use the set width for the initial size, you could set "flex: 2 0 100%" and "flex: 3 .5 100%". This says all three should remain the same size but share the space, but when they drop to another row they stretch 100% to fill the next row. You could also add CSS "media queries" to collapse or hide any of these flex items for tiny mobile screens, say removing the left and right flex items and leaving the middle one, or change the "flex" values in CSS to get larger or small in different ways based on specific device viewport widths. But with flex, all that is now optional as it does a great job of dropping items in rows into new rows as the window changes size.
You will notice that I didn't change the default "align-items: stretch" spacing values, and used the default value ("stretch"). The default makes sure all the boxes in the rows "stretch" to the same height in the row or whatever axis is used. This can be tweaked, so that instead of similar heights, the boxes stretch based on their content, or other alignments. Because of the default "stretch" setting in "align-items", the heights of the cells remain the same, which is one great feature of "flex" you cannot get using floats. I could change this, however, to say "flex-start", and these boxes could extend down their text content in an uneven line instead. As you play with various sizes and design layouts using flex, and start changing the various justify spaces and alignments and sizes of boxes, its flexibility in changing layout will become more important over time.
We just need the HTML5 browsers to catch up and support more of "flex" in CSS.
CSS Style Sheets for Flex: Be sure to paste in my style sheet code into your own website as is. It includes all the "crazy" cross-browser CSS prefixes needed, plus hacks for older browsers. These fixes will allow this solution to work in as many old and new browsers as possible, going forward, and takes care of most of the big issues you may find using flex in numerous browsers. Because "flex" was partially implemented by modern browsers without a real standard or true recommendation, it has created this mess of CSS needed to guarantee your flex boxes will work across many modern browsers used today and in the past decade.
As always, my code choices reflect my concern and care for older browsers and a wider range of users, allowing your HTML websites to reach 99.99% of browser support with very little cross-browser testing needed. That means you can use my solutions knowing they work in a wider range of browsers and use your time for more important web building ventures. :)
One of the problems of HTML5 is the fact that new markup standards are often designed to work in new browsers but not degrade gracefully in older ones. HTML5 does a good job of limiting the number of new elements added to the HTML recommendations. Since 2010, there have been maybe two dozen or so elements added to browsers. Of these, only half have had wide adoption by newer browsers. For elements like <canvas>
, <dialog>
, <datalist>
, and others, you do not need to worry as few browsers support them. And I recommend you avoid them. It is the popular HTML5 elements that remain you must worry about, as older browsers will fail trying to render them without additional help.
Many older browsers, like Internet Explorer series 1-7 and Netscape 4 and 6 series are almost entirely dead. Yet, these browsers occasionally pop up in some places you might least expect. I remember in 2012 going to large corporate convention to present a new web application I built, to find to my horror their own projector tower in the corner of the room only used old Internet Explorer 6! Thank goodness, I had designed my XHTML and CSS to work well in the broken box model and "quirksmode" of IE6. So, my site ran perfectly! But it taught me not to assume the latest and greatest code is important, because in the real world it does! The fact is, not everyone has the latest and greatest web browser!
The version of old web browsers you need to worry about vary. But in terms of supporting HTML5 elements your main focus should be on Internet Explorer 4-8, simply because between 1996 and 2010 these IE browsers completed dominated the browser market. Unfortunately, these browsers were born too early to ever know about HTML5, which really didn't get started until 2007, but was not fully implemented till some time after 2010. For that reason, these IE browsers will completely bomb when they encounter HTML5 layout elements because they simply do not know what they are. Other HTML5 browser issues will pop up in many older Gecko browsers, like early Mozilla and Firefox series, old Netscape 4 and 6 series, and nearly all desktop Safari browsers. I will not go into detail except to assume that any browser made prior to 2014 (year of first real major HTML5 implementation) will struggle with HTML5 elements. Often when an old browser finds a new element it does not recognize it defaults its CSS properties. Example: "display:block" is assigned to block-level elements. The list is extensive. But it cannot really restyle these unknown elements if it doesn't know what they are. It could assume they are text, not markup. So, that is what I will help you fix. My goal here is not to solve every complex issue in HTML and CSS for you below, but to give you a few tricks that will solve 90% of your issues and allow you to move forward quickly knowing you have tackled this very complex issue without Modernizr, Polyfills, or layers and layers of complicated scripting and CSS. I offer you two solution below to help fix issues in Internet Explorer 1-8 fast!
head>
of your web page. This will install these elements into the memory of Internet Explorer 4-7 so that the HTML elements are now recognizable:
<!--[if lt IE 9]>
<script>
document.createElement("header");
document.createElement("nav");
document.createElement("main");
document.createElement("footer");
document.createElement("section");
document.createElement("article");
document.createElement("aside");
document.createElement("figure");
document.createElement("figcaption");
document.createElement("video");
document.createElement("audio");
document.createElement("picture");
document.createElement("output");
document.createElement("details");
document.createElement("summary");
</script>
<![endif]-->
Isolate IE 1-7 Using CSS Style Sheet @import - I suggest you use my "@import" trick to hide all your newest CSS3 and other styles from all older IE browsers. My new "Universal CSS Framework" uses this technique. In fact, this tutorial uses this new CSS system, and allows me to hide more advanced styles from IE 1-7. I can then provide a progressive, simplistic CSS style sheet for IE 1-7 that allows my websites to appear as a simple, white, block-level pages for these older browsers and more advanced CSS for every browser created after that. Your newer browser users will get CSS3 or higher styles and layouts, while these older browsers get plain white linear designs.
First, create a basic CSS style sheet for these older browsers ("OldBrowsers.css") which you add to your web page via a standard link (see below). In here, add any special styles for these older browsers including special styles for the new HTML5 elements you installed above. Note, after you run the script to insert dummy elements above, you will now find they are actually ready to be fully styled! Next, create a second style sheet that has the new "import" CSS rule that will hide your more advanced style sheet from IE 4-7 and a long list of other antiquated browsers (see below). Simply paste this CSS import rule EXACTLY as shown below, then add in a URL to your advanced CSS style sheet. Older IE browsers will only get the first linked sheet mentioned, and your newer browsers will read both sheets. But you can easily add styles in the advanced / imported sheet that will cascade over the first. IE 4-7 will never see the advanced / imported sheet. You can now safely ignore IE 4-7 forever in that sheet going forward using cutting-edge CSS styles knowing those old browsers will never see them. Your newer browser users will always get the import sheet, so that newer browsers going forward will always get the latest and greatest HTML5 designs and CSS layouts possible without breaking in IE 4-7!
Note: You MUST use the @import rule EXACTLY as designed with text and spaces and use of the "all" type. This exact "import" format fails in a number of older browsers for various reason related not just to "import", but use of the "all" media type (IE does not understand "all" in @import), "url" removed from @import, and use of a single quoted URL string around the URL string (old Mac IE browsers fail with this). There are many versions of the "@import" styke sheet rule that enable older browsers. But this one generally is helpful in excluding the main browsers of the past, Internet Explorer 1-7.
@import 'AdvancedBrowsers.css' all;
- Windows Internet Explorer 1-3
- Windows Internet Explorer 4.x-7.x
- Macintosh Internet Explorer 2-4.5
- Macintosh Internet Explorer 5.x
- Netscape 1-4.8
- Opera 1-3.5
- Konqueror 1-2.1
- Windows Amaya 1-5.1
- iCab 1-2
- OmniWeb
To Use this trick, first add two external style sheets links. The first "OldBrowsers.css" sheet should have IE 4-7 basic styles only. The idea is to give these older browsers very crude, simple, white page layouts of content (no grids, flex boxes, etc.).
<link media="screen" rel="stylesheet" type="text/css" href="OldBrowsers.css" />
<link media="screen" rel="stylesheet" type="text/css" href="Importer.css" />
Second, add the following @import rule inside the "Importer.css" style sheet page above, and change the link below to your advanced browser style sheet. Be sure to add all your advanced CSS into this sheet, styles you would normally use in HTML5 and CSS3 compliant browsers.
@import 'AdvancedBrowsers.css' all;
That's it! You now can design simpler white pages with text for IE 4-7, but using HTML5 that works and styled for these older user agents. But, in your "imported" sheet you can safely do your advanced CSS layouts and designs you expect to work great in newer HTML5 browsers.
Here is an example of how "web applications" used to be done 10 years ago using Microsoft ASP.NET WebForms. So, if you see this type of code in a web page or you are used to coding this way, this is NOT how more modern ASP.NET pages will work going forward using ASP.NET MVC CORE. This was first invented in 2002 and has been around for a long time. I like to post stuff like this to remind me of older technologies I once used that might still popup in company servers. Notice the old form with "runat=server" in the "form" element that told the server to process every element inside the form on the server. These strange "forms" always wrapped around every page's content in old WebForms ASP.NET, even if form controls were not present. It managed many parts of the page this way by using HTML's natural form HTTP post format, adding strange new features like hidden postback form fields filled with Viewstate data. Bad design! We often deleted these gigantic viewstate data strings from our projects and recreated the page control "state" manually in the codebehind page. If you see this "form" code below in any web project you might have inherited you should just know its old .NET Microsoft WebForms.
As a Microsoft developer, I like to remember all the different languages and frameworks we used to use when constructing HTML in ASP.NET. Web development technologies have changed 5 times now in the past 20 years, believe it or not! My favorite Microsoft web technology is still a much older design called "ASP VBScript", the original interpreted language that we used to code in (c. 1998). Ironically, Razor Pages in new Microsoft CORE ASP.NET in 2022 is returning web development BACK to this older, simpler, HTML page code model in many ways! Strange. I guess what's old is new again! This proves technology often doesn't improve, but gets worse when we hire the wrong people to re-imagine it and abandon what once worked well. They erase the work of talented people without bothering to learn from them or the past, destroying what was once a great model used by millions of people. I cannot say the same for old WebForms, which in my opinion was written by the wrong people: Desktop Application developers, who did not bother to understand HTML or CSS, much less Web Standards in 2002. As a result, their 15 year old technology is now dying quickly on the vine. Its death proves my point.
Anyway, below is some sample ASP.NET code:
HTML5 by default uses UTF-8 character encoding for all its markup and content. Thus, HTML5 uses Unicode number sets for all its characters. It supports over a millions unique characters, including all the languages of the world and more. But UTF-8 is the form of Unicode encoding used, and means all characters are translated into number sets and stored using an initial 8-bit memory block for each character. Think of Unicode as a giant sheet of numbers mapped to letters and characters and UTF-8 as the specific way those numbers are encoded or stored in memory. UTF-16, the standard encoding used by JavaScript (see next article below), encodes numbers starting with 2 bytes, or 16-bit sets going up to 4 bytes to encompass all the characters in Unicode. HTML5 and UTF-8 uses the same basic system, but starts with a single byte and can go up to 2-4 bytes when it stores upper planes of Unicode numbers.
When software tries to read these Unicode numbers and translate them into actual fonts and letters, it must read the numbers from these bytes in memory or from a byte stream from the server over the Internet. But to read them correctly and extract the right numbers, web browsers and their various parsers need to know the exact "encoding" used when the page and its associated files were created. To do this, most browsers use the server's HTTP response headers, the HTML doc type, meta tag charset values, and byte order marks on documents to determine encoding settings. Knowing how those values are stored in HTML and other files matters. It determines if numbers are stored in one byte rather than two, for example. This is what UTF-8 represents and why it is so important. If the browser did not know which encoding to use, or even if Unicode is used, some or all of the characters would be decoded incorrectly and the Unicode characters displayed would be scrambled. When these numbers are read wrong they are lost and cannot be deciphered.
The confusion behind all these charsets, Unicode, and encoding/decoding schemes means most developers work around the edges of this technology and just accept or "hope" the browsers do their job and interpret everything correctly. This works fine for most English-based websites, as the standards characters used are almost 99.9% of the time map to the older technology called ASCII, which uses the first 128 characters of UTF-8, matching the two numbering systems number-for-number with all the major alphanumeric characters, perfectly. Only 32 of those special command characters will not match. The same applies to UTF-16. So, as long as all your characters remain within the major English alphanumeric ones you do not ever have to worry about HTML5 and how it interprets, encodes, decodes, and stores those characters.
The problems come when you start using "upper planes" of Unicode that hold foreign languages, emoticons, and special characters beyond the standard ASCII ones. There are 17 planes comprising over a million characters and their code points. So, its possible to misinterpret their encoding and decoding. The problem grows when you consider the fact most font sets do not have most of those glyphs built into them. Add to that the issue that many older browsers were not designed for Unicode character mapping, foreign languages, emoticons, or display of older language sheets, like Latin-1. The good news is that because HTML5 is UTF-8 now, all the modern browsers interpret the majority of foreign languages and a larger proportion of Unicode characters, correctly. Many fonts exist that support a vast number of glyphs. And memory and storage of UTF-8 and UTF-16 is now reliable and consistent. Remember, UTF-8 supports over a million characters. It will hold most of the Unicode numbers in 1-4 bytes just fine. It is when storage, encoding, and decoding occur of Unicode characters that you might see issues. The main problem is older browsers and even some newer ones that sometimes mis-identify certain languages or characters used, or jumble the way they are decoded.
In the old days of HTML4.1, the older browsers often defaulted their charsets to Latin-1, or Windows-1252. And so, when foreign languages were used, the browser might or might now have the character code points, sheets, or fonts to interpret and display them correctly. Again, it might be that those characters were pasted into pages from a flawed encoding, so would be returned scrambled. Any data stored in databases that did not use Unicode, would also store the numbers incorrectly. They would then come out scrambled from memory in the wrong code points. Some modern technologies like React, I have read, still have some struggle with Unicode in memory, byte streams, or in the storage of encoded and decoded character sets.
As I mentioned, the good news is that HTML5 now enforces use of good Unicode encoding and decoding. The code examples in this web page are also designed to maximize your chances none of these problems occur by making sure you use the right HTML5 markup and headers to trigger UTF-8 encoding and enable display of Unicode characters. By adding meta tags with the charsets for UTF-8, as well as setting up your software to encode in UTF-8 (which most now do), you are almost guaranteed to NOT have Unicode character issues as the browsers and their various parsers (see JavaScript one in next article) will now know exactly how to decode them. Add to this the fact most ASCII maps perfectly into UTF-8. You still may find some characters that fail to display correctly due to the issues mentioned above. In those cases, I will describe some ways you can bypass encoding problems and directly encode characters in a way that is guaranteed to work for decades to come.
In Unicode, every character is identified with a number represented in memory of the browser, database, or computer as a numeric value called a "code point". The number is often displayed as a hexadecimal (Base16) value, which in turn gets stored or represented in memory as 1's and 0's. This is basically how most characters get translated. Each code point represents just one simple integer, which in turn represents over a million characters listed in the giant Unicode sheet. These numbers can grow as large as 4 bytes or 32-bits, which can hold billions of numbers, if needed. Understand that each special Unicode number represents its own special character in the massive 17 "planes" of Unicode and is uniquely tied to that character alone. It cannot be used by any other. As long as you know the right numbers you can display any character you want, regardless of how they are stored or encoded because Unicode numbers are universal. Know that the storage, encoding, and decoding of these numbers is what gets complex and what is variable in the computer world. Know that HTML5 uses UTF-8 to store, parse and display both its markup and content, but JavaScript parsers use UTF-16 (see JavaScript article, "Character Encoding in JavaScript" below). But as I mentioned, you really do not need to worry about the details of how they operate in these different encoding schemes. As long as you are not reverting back to what older browsers did - encode in old Windows-1252 or Latin-1, or try and trick HTML5 into not using UTF-8, most of your Unicode should work file in most browsers. The modern HTML5 browsers are very smart at figuring out what encoding all your files use, anyway. Modern web servers are designed to assist the browsers in that process using HTTP headers, as well. But what if you want to paste in some fancy Unicode characters into your content, or display emoticons, or special characters and scared you might see unknown or scrambled characters. There is a risk. But I am going to show you how that works so you will never again be fearful of using Unicode in your web pages.
Unlike the limited character sets that came with browsers years ago (older ASCII-based encodings like Latin-1/ISO 8859-1, Windows-1252, etc.), Unicode number values are pulled directly from sheets that come with operating systems and browsers. The problems that remain, include the fact that many fonts stored on laptops and older desktops do not often include the FULL Unicode character sets. The web browsers today use tricks to fix this issue, like picking custom fonts from the user's set needed to display many multilingual characters, glyphs, and emoticons. However, this might still fail because developers often assume everyone has the right fonts or do not assist the browsers enough by providing fonts with the glyphs needed. Asian characters, which are more pictorial, often fail to display in web browsers around the world as they require very accurate glyphs. The problem was compounded by older browsers like Internet Explorer 1-6 and others that did not come with multilingual font support, so would fail to show many types of Unicode characters. These older browsers also were not designed to pick "alternative" Unicode-supporting fonts like later versions. And so, if they could not find the Unicode character in the author's set font in CSS, they would display a "?" or "unknown" error for that character. The problem was compounded by the fact the charsets used often included custom operating system versions of characters, like Windows-1252 which came with characters and numbers that did not match to Unicode's versions of those same characters. So, you can see the variety of issues that have occurred with Unicode over the years.
To help you overcome all these issues with Unicode, I have created a checklist below of things you can do to maximize your chances that your web page's Unicode characters work in as many browsers as possible:
Now that you have all that info, lets discuss the types of character references and how to use them.
What is in a Name? You have many choices in how you use Unicode characters in your web pages. The confusion online is often not about Unicode characters, but all the crazy names for these types of markers. You will hear the terms "Entity", "Escape Characters", "Encoding", "Character Reference", and more! So let's settle what the names mean first:
Now that you have all that info, let's discuss "types" of character references and how to use them. Once you have added your meta tags and are using HTML5, you can be confident you are telling most browsers you are using UTF-8 (see my HTML5 element section on <html>
). Once you do, you are now free to start sharing Unicode characters directly in your page. The way you reference Unicode characters in HTML pages is variable. Other than pasting or saving raw Unicode characters in your HTML documents, the main way you can display Unicode is to bypass the encoding system and use "character references" directly. This technique allows you to use plain ASCII letters and numbers, in combination with a few special characters like "&" and ";", to represent Unicode directly. But you can also just push Unicode characters (like foreign languages) directly into HTML5 pages. The character reference Unicode alternative I have been mentioning was designed to allow you to use plain ASCII alphanumeric types in displaying Unicode without encoding or decoding, and is supported in nearly all legacy browsers and computer systems. But, to be thorough, there are four (4) main ways to use Unicode character sets in your web pages:
Let's look at a few popular HTML "entities" in Unicode that have been used successfully the past 20 years. Again, these are simply single Unicode character reference that can be pasted directly into your HTML pages when you need to use a few special characters. They also work well in older browsers because they fall inside the popular strings of English ASCII character sets (256 characters) and map to the exact same numbers or "code points" as used in Unicode/UTF-8 (which HTML5 uses).
<q>
, supplies these quotes in a more reliable fashion for us already and is a better choice: Hi there(<q>Hi there</q>).
If you want to use the full range of Unicode characters references in your web pages, simply Google it online. There are thousands of pages online listing the full Unicode code point sets and their numbers.
One Final Note About Unicode and ASCII: As mentioned, some older web sites years ago used another form of ASCII called ANSI in Windows. All of ANSI's 256 characters seen in older HTML browsers and applications map ok to HTML5 and UTF-8 encoding EXCEPT 32 "special characters" that were proprietary to Windows. Those special characters - like the currency symbol, special quotes, trademark symbols, and others - DO NOT APPEAR in UTF-8. UTF-8 uses a different symbol set for those characters. That means where those characters were used might now show error markers today. In most cases, these old pages are either still delivered in the charset needed to display them using fonts that still support them, modern browsers still support ANSI, or the characters have already been translated to ASCII or UTF-8 versions. But if you see broken or jumbled characters in a web page, its likely because those special 32 characters are MISSING in Unicode and UTF-8 and should be removed or translated in the page to their equivalents in UTF-8. Until you do that, they are simply unknown characters. You can do that by either translating them to escaped numerical entity values or replacing the raw text with Unicode text which then maps those to their equivalents in UTF-8. So, just a heads up if you see broken characters in HTML5 browsers in some pages. Now you know why!
Most young web developers building applications in ECMAScript today do not know how scripting works in terms of text and character manipulation. Creating these gigantic JavaScript API technologies, while not knowing how scripts decode web pages, is a strange aspect of today's web development environment. I want to show you how JavaScript works with Unicode and differs from HTML's encoding so you have an idea of how the two communicate and work with character data. It is this failure to understand decoding and encoding that is now causing problems in newer platforms like React, for example, and how it streams upper planes of Unicode correctly on its servers and in browsers. In the end, developers forget that manipulating strings and markup is all that JavaScript really does because the dominant media in 2022 in HTML is still displaying readable alphanumeric characters to Human Beings. Fancy scripting of web pages does not change that fact. This is why HTML and CSS will always have a longer shelf life than ECMAScript in web browsers over time, in my opinion, despite this desperate push to JavaScript the whole Internet. HTML is just a faster, more predictable, more manageable, more secure, cleaner, simpler technology than scripts when distributing millions of web pages and terabytes of data online. Can you tell I'm biased? I hope so.
For now, I will skip most of the detailed discussion on general character encoding, storage of characters in bits and bytes, and the like, and assume you have a basic understanding of those terms. You can search for those terms online, if you need a refresher course. In this article, I am simply going to cover how JavaScript uses Unicode, how it decodes characters, and how that relates to HTML5's encoding system and its various markers. I found this topic completely confusing with very poor documentation online until I finally pieced together the answer of what is really going on. This discussion is in no way authoritative or exhaustive. But this may help you in your own understanding of JavaScript and HTML as you integrate the two together in your web pages and come across weird bugs and issues. The way modern browsers use ECMAScript to decode/encode HTML and character data is just not what we assume.
Unicode is the future of how languages around the world are used on the Internet and beyond. "Unicode" is just that, a giant code table of all the characters of all the languages of the world and more mapped to numbers. Unicode is not about the "encoding" or "decoding" of characters, or their storage, or even about the display of those characters in web pages. Unicode is simply a giant listing that connects characters to over a million numbers (called "code points"). How those mapped numbers get stored in computer memory (in "code units" or bits and bytes) is what encoding does and what the technologies called "UTF-8" and "UTF-16" manage. But Unicode itself just controls the mapping of characters to their associated numbers. It is the Unicode tables that web browsers need when they use those numbers to then get the languages and characters they represent on computer screens. But it is the encoding schemes used by the browsers behind the scenes that matter; the script engines and markup parsers that parse, decode, encode, store, and extract those numbers over and over again in web browsers and servers that decides how well the overall character display system works. Get that wrong and everything is a jumbled mess!
And so it is the "encoding" and "decoding" parts of this story that make this interesting. When Unicode numbers are given to a browser, for example, and get stored somewhere, they get put into bytes of "1's" and "0's" in your computer. When you see "UTF", think of it as a computer program that changes computer bits in memory to physical numbers and back to bits in memory again. Unicode translates the numbers returned in both systems into actual characters on a screen. But "UTF" is about how their numbers are stored and read. That is encoding. Unicode tables and "UTF" systems are two systems that HTML5, JavaScript, and many other computer languages use together when reading, encoding, decoding, and storing characters and numbers in your web pages. Unicode and UTF working together is what displays HTML page layouts, runs JavaScript movement of textual data in and out of the Document Object Model, and displays all the pretty characters and numbers you have been reading on your phone or computer screen.
As a quick example, this is what code looks like when translated from various numerical formats to a visual character. The first number is an HTML-friendly "entity" that directly translates into a Unicode number that directly translates itself into a character the browser displays.
♥ = \u2665 = ♥
There is a slight difference between the two encoding systems, UTF-8 and UTF-16, the most popular Unicode encoding systems currently used on the Internet. It is important you understand them in case you start building large websites that use foreign languages or characters and run into issues with garbled characters returned. If that happens, know that it isn't a problem with JavaScript, HTML, Unicode, foreign languages, or your choice of emoji characters. It is most likely a problem with how you encoded your web pages then decoded them using UTF-8 or UTF-16 in HTML and JavaScript.
UTF-8 is the simplest system to use when encoding Unicode numbers. Such numbers are called "code points" as they represent actual characters you see in web pages. When UTF-8, for example, reads a letter it translates that into a Unicode number using the Unicode table. That number then gets translated again into memory or on your hard drive as a 1-byte or 8-bit number stored in binary (example: "A" = 65 in Unicode = 0x41 in hex = 01000001 in bits, the language of computers).
In the old days of personal computers (1980's), everything in the English language and in numbers 0 to 9 was stored in an encoding system called ASCII, which also used a full 1-byte of memory (actually 7-bits of its total 8-bits was used). It could support 256 characters in that byte of memory, so supported the full English character set, numbers 0-9, and a variety of extra characters. (You can read more about ASCII online.) After ASCII came on the scene, every language and country tried to come up with their own mapping files to their own characters and numbers, creating a mess. Each code file that mapped numbers to characters meant operating systems like Windows had to store all those code files and pull them up when a foreign language had to be decoded and displayed.
Unicode was invented to put all those mappings into one code file and simplify everything. Unicode now maps to 32-bits or 4-bytes of numbers representing every possible letter, number, and character conceived (over a million unique characters!). I have read only 130,000+ of those code points are actually used, so it has room for many more! When HTML5 was introduced they decided to embrace the Unicode standard by using the most basic encoder for Unicode they could find that would use the least memory possible. That was UTF-8.
UTF-8 starts with 1-byte to hold all the basic ASCII characters and goes to 4 bytes as needed when storing upper level Unicode character numbers. UTF-16 works exactly the same except for one major difference: UTF-16 starts with 2-bytes instead of one as the minimum bytes needed to store even the simplest of characters and goes up in pairs of 2-bytes to 4 bytes like UTF-8 for higher order character numbers. What that means is they work close to the same except for that extra byte needed for UTF-16 when storing lower order characters like ASCII. Remember, ASCII is 1-byte so fits perfect with UTF-8 as it and ASCII store basic English letters and numbers exactly the same in computer memory. But UTF-16 would start with 2-bytes. Because of UTF-8's compatibility with ASCII in terms of byte storage, HTML5 (which by default always uses UTF-8)easily works with old web pages and scripts encoded in older ASCII systems, Latin-1, Windows-1252, and other English character encoded systems. HTML5 has thus become fully backwards compatible with older text and technologies for storing text, markup, and scripts using UTF-8. You never see any issues between HTML5, HTML4, XHTML, etc because of this cross-compatibility with older 1-byte, 8 or 7 bit storage number systems. That is important! UTF-16 reads ASCII perfectly fine, too, but it is that extra byte it uses in storage that means UTF-8 and UTF-16 cannot read each others values from storage reliably with out "decoding" each other first. It might be that most of the time they can get away with it as the extra byte in UTF-16 is usually ignored by UTF-8 when reading ASCII numbers. But it comes with risk.
Remember: UTF-8 is not UTF-16 when it comes to storage of character numbers!
If a small Chinese character or emoticon got pasted into your English text and the decoding systems were either ignored or it was assumed all your text is 1-byte character code, you likely would see lost or scrambled characters with the wrong code points when you retrieve your text back!
JavaScript (ECMAScript) supports Unicode like any other modern computer language does. But, JavaScript uses a UTF-16 "encoding" system when reading and storing its Unicode numeric values internally. As we mentioned before, HTML5 uses UTF-8 for reading and storing its Unicode numbers. Both encoders are designed to read these character numbers encoded in other schemes through the process called "decoding", which translates characters number from one encoding into their own number and memory scheme. As long as they are told accurately what those encodings are "encoded" in, they can decode them accurately. They know how to encode their own Unicode numbers, but they might not know how to decode others. That is why most systems fail when this process of knowing what someone is encoding in fails or gets misinterpreted. If a piece of software, like a JavaScript engine, does not know or cannot figure out the encoding of a foreign document, data stream, or string, that is when trouble starts simply because it might translate those bits into the wrong values.
In the "olden days" of the Web, around 1998 when JavaScript came online, it was decided JavaScript should use UTF-16 and start with 2-bytes for every known character and move up to 4-bytes (variable length) when supporting the full set of global characters in Unicode. This is how JavaScript and ECMAScript was designed long ago so it would not run into problems parsing the first 65,000 characters supported at the time for a typical 2-byte sequence, potentially supporting global languages back then using various encoding schemes. As mentioned, HTML5 today supports UTF-8 encoding and storage, initially using 1-byte of memory for its code point numbers. It would only support 256 characters in storage initially, but go up to 4-bytes like UTF-16. And so today there is a small gap between how JavaScript and HTML5 store Unicode characters. Despite their encoding differences, however, that is not a big deal. I will explain why.
Modern JavaScript "engines" in browsers, when it comes to ASCII characters (a-z, 0-9, etc), uses UTF-16 to read and manipulate them, but doesn't always store them in 2-bytes. Most developers don't realize that. JavaScript in many scripting engines (Like Chrome's V8 engine) uses UTF-16 when it reads its own source code as well as HTML and text in 2-byte block increments. But it still may store many of the lower order characters, like ASCII English characters, in only 1-byte like UTF-8. That doesn't create a problem when JavaScript decodes UTF-8 in HTML5, as all English text in ASCII matches UTF-8's 1-byte sequence, anyway. Old browsers and web pages encoded using old ASCII-friendly code pages, like Latin-1 or Windows-1252, also use the first 128 characters of ASCII and UTF-8 in memory, so are often interpreted and stored the same as ASCII sets as they all use the same numbers. Many common open-source JavaScript engines developed since 2008 still run many of the scripting engines in browsers, and translate the first 128 character numbers stored in 1-byte / UTF-8 quite easily. JavaScript engines like V8, I have read, now store these ASCII characters as 1-byte for speed, for example, and do not use a true UTF-16 storage mechanism for ASCII lower "plane" characters. Otherwise, they do use UTF-16. The main thing you need to know in understanding the two systems is that they work in harmony with lots of fallback mechanisms in place, especially when encoding and decoding strings and code used between them that involve the core English language characters and their numbers associated with old ASCII.
The problems start when JavaScript reads upper plain Unicode numbers (not ASCII numbers) stored or embedded in UTF-8 web pages.
Example: If your HTML page or script file, encoded with UTF-8, stores the "¢" or cent character (an upper level Unicode character, btw) directly in the file, in UTF-8 that becomes a two "code unit", or 2-byte set, as "\xc2\xa2"
. If JavaScript decodes it from UTF-8 correctly, that double-byte value gets encoded then re-encoded in JavaScript's UTF-16, or 4 such hex set, as "\xc2\x00\xa2\x00"
. That is how it is supposed to work!
Decoding HTML5 Characters The main way JavaScript and HTML interact is through the decoding of each other's values (often using byte streams) then encoding them back into their native encoded values in memory. But both parsers and engines that read JavaScript and HTML in browsers and on servers have many ways to detect each others encodings. It is those detection schemes that make the whole process run seamlessly. It is when those schemes break down that you see problems. So as long as they sniff each others encodings in UTF-8, UTF-16, Latin-1, ASCII, AND those pages and text are encoded correctly, your browser, computer, and server will know how to correctly translate them. If that communication breaks down, that is when characters are scrambled or get lost. That is what happens often in foreign language systems. The extra memory or bytes USED between UTF-16 in JavaScript and UTF-8 in HTML5 does not really matter that much. It is how they are decoded that does. It is when you start trying to decode or encode these higher order "planes" of Unicode characters you might get tripped up between the two systems if you do not tell HTML and JavaScript what files are encoded in or fail to encode them correctly in the first place. That encoding issue is a common problem in IDE's or software systems web developers use to create web applications, as most encode, or don't encode, the same or consistently. That inconsistency is what trips up some developers when using higher order Unicode languages on say English-speaking computers or platforms. As long as they are encoded right, everything works. When they do not, it does not. So keep that in mind.
For example, when you create a JavaScript "source file" with JavaScript code for your web page to link to, or type HTML markup in an HTML file with special characters or icons, in most modern software applications your file and its characters will either be encoded as a UTF-8 file explicitly or will be closely associated with an older format like ASCII or Latin-1 on English-speaking platforms that does not know how to save or encode these special characters. That is when problems could occur. For now, let's assume the software is using UTF-8 so can encode higher Unicode characters correctly. That script file with special characters is then saved and encoded as UTF-8 text and placed on the web server for your web page to consume.
When JavaScript in your browser downloads the UTF-8 file and tries to read it from the web server, it will sniff the file using various techniques to figure out which of these encoding systems its encoded in. It will then decode parse the file, decode it, compile it, and run it in memory using its UTF-16 encoding system. This is a seamless process. Most JavaScript engines now expect script files in your web pages to be encoded in UTF-8 or ASCII by default and so just decode and re-encode all of its script files stored in UTF-8 to UTF-16 very quickly. As mentioned above, most encoders simply store each character in a single byte, anyway, if its using standard ASCII lower order character numbers. If any of these files or code have higher order foreign languages in them, those characters will require 2-4 bytes in storage, however. It is then critical that the numerous extra bytes needed to store them in JavaScript's UTF-16 decode the UTF-8 correctly. As we mentioned, if that gets handled wrong, that is when problems could start in your web pages or in JavaScript. But let's discuss the process of decoding in detail below, so you know how that translation actually works in a hierarchical fashion when reading simple script or HTML markup pages.
Before JavaScript can process its own scripts (either inside an HTML page or downloaded via an external link), the file containing those scripts must be loaded into the script parser as UTF-16 encoded character sets, first. To read and decode all this text, a careful set of processes runs to download and decode the script file as follows:
As you can see, JavaScript and your browser have a rich set of tricks to use to make sure it decodes your character data correctly into its native UTF-16 number storage system. When JavaScript decodes your text files, its source code, or its script files into UTF-16, the script engines and parser in browsers figure out how to do all that using one of these many techniques above to make sure characters are encoded and decoded properly. So it has lots of fallback mechanisms to make sure that translation to UTF-16 is fluid and accurate. In addition, I read that the "V8" JavaScript engine behind decoding and encoding of pages actually stores all your HTML markup and DOM ASCII strings as true ASCII (like in UTF-8), so code like HTML tag names do not double in size and are easily transferable between encodings. With these particular byte sequences you don't really have to worry about how the actual bits are encoded. Source files are expected now to be encoded by default with UTF-8, as are all new web pages delivered by the web server. So in the end, the movement of characters between HTML and JavaScript are pretty seamless between the two encoding types now and should not cause issues. Just remember to encode your files in UTF-8 and JavaScript and the web server will handle the rest quite efficiently!
As I mentioned many times, because 99.9% of English uses the old 1-byte 128 character ASCII set, they translate one-to-one in all encoding types, for the most part, without ever having any real issues in all these decoding systems. So you are doubly safe! It's when you use other higher-level Unicode numbers, languages, and characters that you may have to be vigilant and make sure your script files are encoded correctly and follow the rules.
Last thing, you can skip many of these encoding issues in HTML and even JavaScript by using "character references" to specific Unicode characters directly in your page! If you need a couple emojis or special characters in your web page, rather than pasting them into UTF-8 encoded documents and risking tripping up UTF-16 in JavaScript, you can use these entities directly as they do not require decoding! These are actually interpreted "codes" written in plain English-ASCII that can be translated directly into Unicode by the browser and any JavaScript parser, bypassing decoding/encoding completely. I use these a lot in HTML for special characters or icons I need, but where I don't want paste the original character into my web pages or wrestle with a possible encoding issue between UTF-8 and UTF-16. These take several forms, including HTML "escape codes", "named character references", or "entities". In general, all these point to the same characters using numbers with an HTML-friendly prefix, like "&" that triggers the parser to translate them into Unicode directly. These are often in numeric or even text name flavors, both which work the same in displaying the character or emoji you might need! They are also easy to remember and quite helpful in pages that need glyphs, artwork, foreign currency, or other special characters.
This Unicode entity below is 100% safe to use. There are thousands more online you can Google! Just paste your Unicode character reference into your web page using the ampersand numeric or text name version, like so:
Use "©" for the © copyright symbol
Before I go into this complex knowledge-share about such a simple subject as "localhost" below, let me clear up one thing about new technology today that has increased confusion. This "localhost" information below is just some of the strange changes that have occurred recently when working with technology on modern OS's in 2022 that none of these companies bother to tell you about. We are all supposed to have all this shared intuitive "inside" knowledge in this industry, which is silly. As Einstein has noted, if you cannot explain something in simple everyday terms, its meaningless to millions of people. Truly intelligent people know this. :)
"localhost" is often used by developers when building websites on web servers located on their personal computers. Developers often set up a local development web server on their computer, assign the loopback "localhost" domain name to it, then test their web application in their browsers using "localhost" before pushing them to live web servers online. The "localhost" name is thus assigned to the developer's default web server. But "localhost" is a strange little name, one missing the usual dot syntax of standard URL's yet often having a long port number attached (example: http://locahost:12345). Over the years, I have seen so many people confused by "localhost". So let's lay out the facts so we all understand how "localhost" works. To do that, I want to cover some helpful info on "localhost" and loopback IP's to help with the confusion, as there is a lot of "junk info" thrown around online by a lot of people that is incorrect and incoherent.
"localhost", when typed in a browser or resolved in your computer, simply refers to your local machine. Often network people will just call it "local" or "home". It does resolve to a number of "internal" IP addresses. But those often point back to your computer again. When typed into the URL of your browser, it is not supposed to go out onto the network or Internet and resolve via DNS, however, like most URL's in the browser will do. It is not even supposed to go through your network card or NIC and seek resolution beyond your local computer. It is simply designed to bypass the network and map back to your local computer. But strangely, it can resolve outside the network, as we will see.
"localhost" is sometimes called "local", which implies it maps directly back to the application or computer that called it using an internal IP assigned to it. This is the local machine, as mentioned. How it does that varies by OS and device, however. By default, "localhost" should NOT connect to the network when resolved from your browser. It should not go through your NIC or network card, or even through the firewall or be contained by any ports used. It also carries with it your full "local user access" credentials in terms of computer permissions, as opposed to network user permissions when a true domain or IP is used in your browser. As such, use of "localhost" carries with it special privileges, and so should be free of network, IP, firewall, or user access restrictions with all ports open to it. "localhost" seems to have a lot of freedom and power on your computer. That's important to know!
As I mentioned, "localhost" is often mapped to a "loopback" address or IP, either internally on the computer via the OS, using some network addressing system, using special software, or some other internal DNS system. It depends on the server and device. In the past on personal Windows computers, this was handled by a simple text "hostname" file called "hosts" (%systemroot%\system32\drivers\etc\hosts). But since Windows 7, this has been disabled and now managed securely by other OS systems on personal computers. This was done in order to address security concerns and prepare for replacement of IPv4 with IPv6 where old loopback IPv4 address would no longer work. Often these internal PC systems control a priority IP mapping list for "localhost" thats secure and prevents malware or outside network devices from connecting to the network as "localhost" or an internal IP from getting access to the network. These new systems still work with the host file, but control mapping of "localhost" to "::1"(IPv6) and "127.0.0.1"(IPv4) network "loopback" addresses elsewhere by default. It is important to realize, when you type the IP instead, these loopback IP's go through the network layers while "localhost" does not. The "localhost" loopback interface bypasses have special properties that bypass any local network interface hardware or NIC, and allow software internal to your computer to listen to this "internal" domain name and resolve it.
Below are two optional "host" file entries you may see commented out in your host file (%systemroot%\system32\drivers\etc\hosts). In the past they would map the domain name "localhost" to loopback IP's that route the name back to your computer. In Windows this is now handled by your computer's OS internally:
127.0.0.1 localhost
::1 localhost
You can test still test if these mappings are still assigned to "localhost" by typing in a command prompt on your computer the following: ping localhost
(uses whatever IP is assigned to localhost, but often returns an IPv6 number like ::1, which is assigned to locahost internally) or ping -4 localhost
(forces ping to use IPv4 and often returns the IP of 127.0.0.1 assigned to locahost internally). If you see the two IP's assigned in your command prompt they are already mapped for you!
"localhost" is often by default also mapped to your local computer's various listening devices or software (i.e. your local web server), but the internal IP's above are not. Confused yet? Windows IIs on 7, 8, and 10 will have no binding by default to these internal IP's, only "localhost". This is usually limited this way for security reasons now by the operating system in your computer. "localhost" is a pointer back to your local host or the computer independent of any internal IP assigned to it. In addition, "localhost" uses the loopback or "virtual network interface" created by your operating system to bypass your computer's network hardware, like your network card or NIC, and loopback to the computer itself (always over port 80, by the way: http://localhost = http://localhost:80). In addition, IIs Express's web server in Visual Studio connects and works in the browser URL with "localhost" but without "127.0.0.1" or IP resolution, by default. You can change the configuration on your web server to accept these special loopback IP's (see below). But "localhost" will resolve to the web server without it. The same applies to IIs on a Windows Server. The loopback internal IP addresses associated with "localhost" are often not supported out of the box on internal default web sites. Typing "127.0.0.1" in your browser will often fail to connect to your server, for that reason.
"localhost" has nothing to do with outside browsers and computers in your network that may try and connect to the default website on your local computer. Remember, "localhost" refers to your computer using its "internal" IP's, not from any "external" IP's, the latter which resolve outside your computer. Your computer can be assigned several outside IP addresses, depending on your network, NIC card, etc. One is supplied internally by your router or corporate network using DHCP. But your router is assigned one externally using a "static" IP assigned to your network (i.e. router) by your ISP or host provider. That means, if you are inside a network, like a home DHCP router where the router has assigned your computer an IP (like 192.168.1.75), your computer name and its IP would still be accessible by outside computers inside your network, but not your web server assigned "localhost" internally. It is only mapped to "localhost" and accessible via your computer. Notice again, your internal loopback IP's also will not have access to your web server and website by default, either. That is because your web server by default will not accept ANY IP, internal or external. It only responds to the loopback text string, "localhost", by default. When any device (even your own) uses those DHCP IP's to try to connect to try your local computer and or web server, the ping packets will pass through your physical network interface, try and connect to local IP and your web server, but fail. Just realize that "localhost" has nothing to do with control of your web server or access by outside IP addresses or even your NIC card. Your local web server by default only requires the "localhost" Host Header name sent by your browser and the virtual loop back interface on your computer to directly resolve. When you type "localhost" in your browser on your machine, the browser sends the packet requests and a default port without any name or DNS resolution call, physical hops, network calls, router calls, or special IP addresses when connecting to your local web server.
Use of "localhost" is thus a very different system than how traditional browser URL's and IP's resolve. It took me awhile to fully understand that because I assumed everything resolved across the network using IP's, even if locally resolved. Not with "localhost". It is a special baby, indeed!
The strange thing is, the domain called "localhost" also exists outside your own computer in external networks as well, including the World Wide Web. They say it is a reserved domain name intended for local IP address resolution only, representing the current computer it is used on. But some network admins will tell you that "localhost" is also a top-level domain (TLD) online. Others say it's simply a "hostname" local to your home computer only. But oddly enough, both are correct! It does act like a true "domain", like the ".com" name, and has a reserved one called ".localhost", too! It has to resolve this way in cases where DNS calls "leak" out onto the web looking for "localhost". As such DNS experts have asked local DNS systems and network admins to always assign "localhost" to their own domains and subdomains by simply attaching ".localhost" to the end of anyone in a network with a domain trying to call outside a computer for "localhost". Doing this prevents DNS systems from attempting to resolve the unknown "localhost" domain and prevent it from seeking resolution outside the network to the top level DNS servers. That allows for special cases where non-Windows or other PC's that don't capture these local unresolved domains correctly flood the Internet trying to find unknown "localhost" website domains online (like http://mysite.localhost/)
So, if "localhost" is mapped internally back to your computer, how is that managed and how can you customize it, and why are we stuck with this weird loopback name with no IP? As I mentioned, "localhost" is often mapped to a series of loopback addresses internally on the computer to prevent it from being leaked out onto the network. In the past on Windows computers (before Windows Vista), this was handled very simply by your hosts (see above) file. This host file still works. But since Windows 7, this has been disabled and now managed by the OS. This new internal PC system now contains a sorted priority IP mapping list that's controlled by the Windows registry settings. It allows for the new IPv6 protocols of the future to also be assigned "localhost", but also prevents malware or outside network devices from connecting to the network as "localhost" using an internal IP and getting access. (so kind of a security fix?) This new local IP mapping system has meant the old "host" file entries for "localhost" are no longer needed and commented out, causing even more confusion!. The top IP's now mapped to "localhost" by Windows is "::1" (IPv6 loopback), one of several internal IP addresses, I am told. Most software systems will only listen for the native "localhost" header anyway, ignoring the IP. But just know, you can still open the host file and map additional IP's to "localhost", even external ones your browser might use, especially after you update your web server to listen for the internal IP addresses (see below). Keep in mind when it comes to your local web server (if you use one) still isn't mapped by default to these IP's nor does it listen or accept any of them, even if "localhost" is mapped to these IP's, internally.
The problem with using "localhost" to resolve browser URL's or other software is it's not really a true URL that gets resolved externally in DNS with normal packet processing and name resolution like most public websites do. As such, it makes testing web sites difficult and inaccurate from how a typical HTML website and server might perform using DNS, routing to servers in and out of networks, carrying security like SSL/TLS, etc. It has really become quite a mess for web developers! If the "localhost" name is used for testing, its local to that person's machine only and their web server, which now cannot be accessed or shared with anyone else to test externally. It also bypasses the "Host Header" web server system where an IP and hostname work together to resolve what a web server receives as far as the request goes coming from the browser. As mentioned already, IP addresses by default are not resolved in a typical web server running on a Windows computer now. More on adding that below...
"localhost" has other strange features in Windows computers. In Internet Explorer browsers, when inside a Windows network but on your local computer, typing any name in your browser's URL string - any text string without "." dot representing the physical name of a computer or server on the network - tells IE to pass your "local access" Windows credentials to whatever computer or web server is mapped and listening to that name on your network. This includes the name "localhost". So typing that name in your browser will also pass your local user credentials into the browser to authenticate with your local server now, with "elevated" privileges! Again, thats atypical of how most web servers authenticate users. If you go outside your computer to a computer or web server elsewhere in your network using such names of boxes (without a "." syntax in the name), IE will again pass your network user privileges as it goes through your network card. These windows credential systems thus apply to non-localhost names, too, and to any server name or IP that gets resolved or routed inside a corporate network where a domain name resolves (example: http:/bob/ would take you to the "Bob" computer name in the network, looking for a listening web server on "Bob"). In that case the browser again passes your network credentials because the URL has no "." in the name and assume its only local. For this reason, in the old days, we used to create intranet corporate websites inside the network on machines (like "SpongeBob", "Homer", "Bart", etc.), add Windows Authentication to their sites, then add their server names in the network with known IP's to our host file or via corporate DNS so users could route to the IIs servers from those named boxes. But we had to add the IP of the box to the web server so they could be read externally. "localhost" was then not needed locally when developing sites, just the IP or box name added to the web server. We used the box names with the advantage that credentials were passed in Internet Explorer, too, allowing anyone in the network could access each others servers. But again, "localhost" did not help us with any of this.
In this sense, in the "Microsoft World", "localhost" behaves like a network name in terms of Windows Authentication, but not as a true external website URL where such authentication and credentials were passed using network box names. That is why on Windows, "localhost" appears to behave like any other computer name, passing credentials like any network address name does in the browser, yet only locally. Its like a "second name" for a computer every computer now has. It's no different than having a computer on your network, typing it in a browser, and seeing a computer name appear with all its public web sites and shares listed. The one difference here is that your credentials on your local box allow full local access, not domain-level network access. So your rights are increased when using "localhost" in terms of logging into your development website. That is how localhost is designed by default on Windows IIs. It is setup with your IIs web server to listen for "localhost" and give you full access "user" access (and often administrator access) beyond what a typical client-server exchange should have. If you try the loopback IP of "127.0.0.1" (having the "." means no credentials are now passed to "localhost" websites) in IE browsers, or via a real IP address in the browser, it assumes you are routing somewhere using an IP (even though its a loopback address), and thus seeks an IP on or off your network, and so does NOT send your credentials over the wire. Wow, that idea added more confusion for me. Because "localhost" is a special loopback IP address unique unto itself, it resolves internally on your computer but doesn't pass credentials like "localhost". And as we have seen, may or may not resolve to locahost in the browser or to a web server, unless manually added. That is because your computer is not resolving the IP to "localhost" like a normal DNS would. Nor is your web server set up to listen for the "127.0.0.1" IP, either. That is why typing that IP often fails to resolve to "localhost" in your browser OR find your local default web server and website setup by default with "localhost" (Host Header to your local web server using just the IP is thus lost). But the main idea here is that credentials are also not passed like in "localhost" using the loopback IP of "127.0.0.1".
By default, your local web server, IIs Express, or IIs does not bind to any internal or external IP's, which was new to me. So, typing "127.0.0.1" in a browser will fail, by default. As mentioned, "localhost" is a unique name so could be bound to a number of different internal IP's and loopback addresses. But that has nothing to do with how your local IIs web server is setup on most new computers with web servers running. The "hosts" file on your computer, however, can still be used to change that and map "localhost" explicitly to any IP you like. But often, by default, that's handled by the computer and version of OS you are using. For that reason, newer servers never use IP binding for "localhost", even the default and common IP of "127.0.0.1". So, if you want to resolve loopback IP addresses like "127.0.0.1" so they connect to your "localhost" website, it means you need to add these IP-localhost mappings manually to your hosts file first AND second change your web server binding settings so they listen to any IP address you assign to localhost. That idea threw me for a "loop" when I first started typing "127.0.0.1" in my browser and it failed to connect to my local website. I could not resolve the "127.0.0.1" IP to my "localhost" website like in the "old days".
One of the tricks you can do as a developer to resolve this when using "localhost" and "127.0.0.1", since "localhost" is mapped to the loopback IP elsewhere behind the scenes now, is open up IIs or IIs Express and set the default bindings for the local website on your computer to accept "all unassigned" IP's (under "Bindings"). You then need to open your "hosts" file (%systemroot%\system32\drivers\etc\hosts) in Notepad or a text editor and add an entry "127.0.0.1 localhost" to the file and save it to make sure that binding is set on newer computers. Only do the latter if you feel that loopback address is not being assigned to "localhost" by the OS. Make sure you open the file with a right-click, then choose "Run As Administrator" before you do. After you do this, when you type the loopback IP in your browser, it will send the loopback IP to the server as normal, but your local web server and website will be listening to all IP's now when resolving the request. The serve is set to accept all IP's, so accepts any sent. If you use "localhost", the host header name gets passed to your local server as normal but now with the loopback IP and is resolved, as well. "Localhost" only does this because of this "host" file relationship mapping and change to your server binding and the custom binding you manually added in your web server's default website.
Knowing how this crazy "localhost" and "loopback" IP system works took me some time to figure out. So, I'm passing all the nuances of this to you. Now you know! So keep all these settings in mind when using these internal network names and addresses. There are lots of weird and unassumed things going on under the covers that you must be aware of. Understanding how they work together is helpful when things break or don't resolve as you quite expect. Local development of websites in 2022, unfortunately, requires too much specialized knowledge from most new developers. This is because of the people since 2010 now building these systems and frameworks adding unnecessary complexity, breaking a system that worked fine before. They just refuse to think about how new web developers entering the field use these tools and assume everyone else has the same specialized and proprietary knowledge they do. It is a form of stupidity and arrogance, if you ask me. It is unnecessary. That is why I am here to help. Sharing this new information with you has now become mission critical to me!
As I develop websites, I've discovered some tricks when working with HTML pages, servers, and browsers most developers do not know about. I will list these below. Try these below in your browser and see if they do not help you.
<link media="screen" rel="stylesheet" type="text/css" href="styles.css?v=637480615038941445" />
https://en.wikipedia.org./wiki/Root_name_server
<mynewelement style="display:block;background-color:#ccc;text-align:center;border:1px #000 solid;">Can you see the content of my new element called "mynewelement"?</mynewelement>
<div><img src="myimage.jpg" alt="" /></div>
<div><!-- --></div>
<ul><!--
--><li><a href="#">Page 1</a></li><!--
--><li><a href="#">Page 2</a></li><!--
--></ul>