HTML / CSS tricks, you might not know...

HTML / CSS tricks, you might not know...
Page content

In the last years I came across some really useful HTML and CSS tricks, I find really useful and that I would like to share with you.

Sometimes, when you do layouts or CSS eye candy, you need links without a full href and to have a valid link (not an anchor), many people use one of the following options:

  • href="#"
  • href="javascript:void(0)"

The disadvantage of the first solution is, that on click the page jumps to the top, which is often unwanted behaviour, while the latter involves javascript, which also seems not very portable. Well, the solution is as simple as elegant - use href="#!":

<a href="#!" onclick="console.log(1)">A no jump link</a>

Trying to jump to a non-existing element with id="!" it simply does nothing - you could also use other non-existing ids, but I like using #! as default.

With the download attribute you can force the download of a resource. If you provide an attribute value (e.g. download="file.zip"), this will be used as filename. This should be supported by most modern browsers. Examples:

<!-- Force download of file, name is manual.pdf -->
<a href="manual.pdf" download>Download</a>

<!-- specify a different filename, name is also manual.pdf-->
<a href="/dl/2a6" download="manual.pdf">Download</a>

If you use target="_blank" you should always use an additional rel="noopener" to prevent scripting access to the window.opener property:

<a href="https://www.google.com" target="_blank" rel="noopener">Download</a>

BEM - Use Block Element Modifier (box box--highlight box__headline)

Block Element Modifier (BEM) is a CSS naming convention, that helps to structure your content as well as the according CSS:

Example:

<div class="box box--highlight">
    <h2 class="box__headline">First box</h2>
    <p class="box__content">First box content</p>
</div>
<div class="box box--darken">
    <h2 class="box__headline">Second box</h2>
    <p class="box__content">Second box content</p>
</div>

Advice:

  • Put layout stuff (width, height, border, positioning) in container classes (box)
  • Put non-layout modifiers (colors, backgrounds) in extra classes with hyphens (box--highlight)
  • Add classes with underscores for sub-elements (box__headline)

Advantages:

  • Keep main CSS free from theming
  • Make classes understandable
  • Having a specific class for each sub-element is perfect to address with selectors

Autofocus attribute (<input type="text" id="username" autofocus>)

The autofocus attribute allows you to enable immediate typing for a single input element. This is especially useful for login or search forms.

<input type="text" id="fname" name="fname" autofocus>

SRI: Ensure integrity for subresources (integrity="...hash...")

If you would like to have a little extra security, provide the SRI attribute for external JS or CSS files. This also might be used for cache busting, but I have to verify that.

<link rel=stylesheet href=/css/all-styles.min.4404e9bfaa0ef0f07f56206c6023008b8e80806a457b1e12a975d974826d8557.css integrity="sha256-RATpv6oO8PB/ViBsYCMAi46AgGpFex4SqXXZdIJthVc=">

Did you know that you can use specific prefixes and parameters for links to write Mails, SMS, dial a phone number or open a map:

<a href="mailto:name@domain.de?a-subject=subject&body=an-email-message">Send an email</a>
<a href="sms:012345...?body=an-sms-message">Write an SMS</a>
<a href="tel:012345...">Call a number</a>
<a href="geopoint:52.520008,13.404954">Open map</a>

Often it is possible, to provide multiple targets separated by , and there is a lot more like whatsapp, skype and other messengers or marketplaces. Note that these links do not work everywhere, and their function is nearly impossible to verify. So you should treat this kind of links as improvement and not as absolute reliable technology.

Check your IDE for Emmet support (ul#nav>li.item*4>a{Item $})

Emmet is a shorthand for writing HTML by just using CSS-Selector-like syntax and it is available for most modern IDEs. Here are some examples:

h1.topic =>

<h1 class="topic"></h1>

h1.contact+form#address =>

<h1 class="headline"></h1>
<form id="address"></form>

This saves you a lot of time writing HTML by hand. Now try ul#nav>li.item*4>a{Item $} ;-)

Lesser known HTML5 tags (<progress>, <address>, …)

There are a lot of lesser known HTML5 tags for very specific use cases. You should definitely take a look at these:

  • <abbr>
  • <address>
  • <cite>
  • <datalist>
  • <details> / <summary>
  • <kbd>
  • <dfn>
  • <mark>
  • <q>
  • <time>
  • <progress> / <meter>

For a complete reference, see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element

Client-side form validation (required)

You can improve the user experience of your web application by providing client-side form validation with extra attributes like required or pattern="". Some examples:

<input name="username" minlength="5" required>

<input name="email" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$" required title="Invalid email address">

Using text placeholders (Lorem ipsum)

Starting a new website project often requires having some placeholder text passages, until you have the time to put in the real ones. A classic is Lorem ipsum. There are lots of services online for that, I personally use https://generator.lorem-ipsum.info/

Lorem ipsum dolor sit amet, solum posidonium cum in, nam ut mazim prompta iracundia, mea ut eleifend adipiscing definitionem. Ullum feugait cu usu, eu pro deseruisse disputando definitionem. Erant delectus an per, mea modus meliore consequat ei. Ut consul essent usu, ne tantas similique ius, postea oblique ut ius. Facilis periculis eu est.

Using image placeholders (src="https://picsum.photos/200/100")

Same rule applies for placeholder images. I personally use https://picsum.photos

<img src="https://picsum.photos/200/100" alt="placeholder image">

Skipping URI scheme (href="//picsum.photos/200/100")

Today most websites provide https instead of http. However during development, sometimes you don’t want to or can’t use an SSL certificate, which may lead to browser warnings because of mixing security standards. There is a little trick to fix that - just skip the scheme and let the browser decide:

<!-- forces https -->
<img src="https://picsum.photos/200" alt="placeholder">

<!-- use the best matching scheme (the current one) -->
<img src="//picsum.photos/200" alt="placeholder">

This applies for any external URI (also CSS and JS), but beware: If you’re using http://localhost for development and //picsum.photos/200 does not provide http, it will result in an error.

Lazy loading images and iframes (loading="lazy")

More modern browsers support the HTML attribute loading="lazy". If provided this attribute prevents offscreen images from being loaded, until they are required to load / scrolled by. This may improve load times and page rendering speed. Examples:

<!-- only load image when scrolling near it -->
<img src="image.jpg" loading="lazy" alt="big image"/>

<!-- force immediate load of image -->
<img src="image.jpg" loading="eager" alt="big image"/>

<!-- let the browser decide -->
<img src="image.jpg" loading="auto" alt="big image"/>

PageSpeed Insights

If you would like to learn about general best practises, you should take a look at PageSpeed Insights . It provides:

  • A vast amount of information about SEO and performance
  • The ability to check a website - this only works for websites that are available online

If you don’t own a website, you can check your favorite websites and learn from the results.

Normalize.css

Normalizing basically is a way to setting sane CSS defaults across all browsers as a baseline, since some browsers use different default CSS. There are several libs out there, here are some:

Repeating patterns with clip-path and multi box-shadow

You can create impressive repeating patterns with multi box-shadow usage. Combining it with clip-path it is getting even better: Illustration of repeating pattern with box-shadow

<div class="circle-stripes"></div>
.circle-stripes{
  margin:50vh auto;
  width:50vw;
  clip-path: circle(30vh);
  box-shadow:
      0 0 0 5px black,
      0 0 0 10px white,
      0 0 0 20px black,
      0 0 0 25px white,
      0 0 0 35px black,
      0 0 0 40px white,
      0 0 0 50px black;
}  

Debugging with outline instead of border (outline: 1px solid red;)

Often I see border:1px solid red; used for debugging (e.g. to make elements visible). Unfortunately border influences the box model and may result in annoying effects like horizontal scrollbars. In many cases border can be replaced by outline, which does not change the box model:

.debug {
    outline: 1px solid red;
}

Horizontal and vertical centering (display: grid; place-items: center;)

.center {
    display: grid;
    place-items: center;
}    

With flexbox:

.center {
  display: flex;
  align-items: center;
  justify-content: center;       
}       

CSS-only tooltips with content: attr(data-...);

Here is a neat trick for CSS-only tooltips. The problem is, that there is no auto adjustment depending on the scroll position, so maybe the tooltip is out of sight, if it is near the window bounds.

<h1>CSS-only tooltips</h1>
<p>
  This is a pure <abbr data-tip="Cascading Style Sheets">CSS</abbr> tooltip.
</p>
/* [data-tip] is just a selector, you could also use classes with .tip */
[data-tip] {
  position: relative; /* required for positioning */
  text-decoration:underline;
}

[data-tip]:before {
  /* here is the clue: use attribute as content */
  content: attr(data-tip); 
  
  /* positioning / visibility (required) */
  position: absolute;
  min-width:100px;
  margin-left: -50px;
  bottom: 1.2rem;
  opacity: 0;
  
  /* appearance (adjustable) */
  transition: opacity 400ms;
  background: #ffffe1;
  color: #000;
  text-align: center;
  border:1px solid black;
  padding: 3px 8px;
  border-radius: 6px;
  z-index: 100;
}

[data-tip]:hover:before {
  /* make tip visible on hover */
  opacity: .95;
}

Custom CSS for selection (::selection)

Selected text can have custom css:

<p class="copy-text">Lorem ipsum dolor sit amet</p>
.copy-text::selection {
    background: #000;
    color: #fff;
}

If you click on an html button, there is a 3D push effect showing that the click has happened. If you would like to simulate this for a link, there is an easy trick:

a.button:active {
    position:relative;
    top:1px;
    left:1px;
}

To highlight external links, you can use a little arrow without any extra fonts or dependencies.

a[target="_blank"]::after {
    content: ' ↗️ ';
    font-size:0.5em;
    vertical-align:top;
}

Border triangle trick

Did you know that you can use borders to render a triangle? Try the following snippet:

<div class="item"><a href="#!" class="first"><span>1</span></a></div>
<div class="item"><a href="#!" class="second"><span>2</span></a></div>
<div class="item"><a href="#!" class="third"><span>3</span></a></div>
.item {
    height:50px;
}
span {
    padding-left:50px;
}

a:before {
    content:'';
    position:absolute;
    border:1em solid transparent;
    border-left-color:red;
    border-top-color:blue;
    border-right-color:green;
    border-bottom-color:purple;
}
.first:before {
    padding:5px;
}

.third:before {
    border-top-color:transparent;
    border-right-color:transparent;
    border-bottom-color:transparent;
}

This Screenshot illustrates, where the triangle is coming from:

Illustration of border as triangle

You can see that touching borders bigger than 1 pixel are rendered miter. So if the borders touch in the middle and you are just painting one of the borders, it renders a triangle. Isn’t it fun?

Andreas Fuhrich avatar
About Andreas Fuhrich
I’m a professional software developer and tech enthusiast from Germany. On this website I share my personal notes and side project details. If you like it, you could support me on github - if not, feel free to file an issue :-)