Almost every business website needs a quick contact block: call, chat, message, directions. Plenty of people install a whole plugin for this, when all it really needs is plain HTML and CSS, without a single line of JavaScript.

This is the version I reuse across projects.

The HTML

<div class="quick-contact">
  <ul>
    <li>
      <a href="https://goo.gl/maps/xxxxx" rel="nofollow" target="_blank">
        <i class="ticon-heart"></i>Directions
      </a>
    </li>
    <li>
      <a href="https://zalo.me/0123456789" rel="nofollow" target="_blank">
        <i class="ticon-zalo-circle2"></i>Zalo chat
      </a>
    </li>
    <li class="phone-mobile">
      <a href="tel:0123456789" rel="nofollow" class="button">
        <span class="phone_animation animation-shadow">
          <i class="icon-phone-w" aria-hidden="true"></i>
        </span>
        <span class="btn_phone_txt">Call</span>
      </a>
    </li>
    <li>
      <a href="https://www.messenger.com/t/username" rel="nofollow" target="_blank">
        <i class="ticon-messenger"></i>Messenger
      </a>
    </li>
    <li>
      <a href="sms:0123456789" class="chat_animation">
        <i class="ticon-chat-sms" aria-hidden="true"></i>Send SMS
      </a>
    </li>
    <li class="to-top-pc">
      <a href="#" rel="nofollow">
        <i class="ticon-angle-up" aria-hidden="true"></i>
      </a>
    </li>
  </ul>
</div>

A few things worth noting in the markup:

  • href="tel:..." and href="sms:..." are standard protocols, so phones open the dialer or the messaging app automatically. On desktop they usually do nothing, which is why the call item carries a phone-mobile class and only shows on mobile.
  • rel="nofollow" tells search engines not to pass link value to external domains.
  • Use a <ul> rather than a pile of <div> elements, because this genuinely is a list of links. Screen readers will announce how many items there are.

CSS for desktop

The block is pinned to the left edge of the screen:

.quick-contact {
  position: fixed;
  left: 13px;
  bottom: 50px;
  z-index: 150;
  width: auto;
  padding: 10px 0;
  background: #fff;
  border: 1px solid #f2f2f2;
  border-radius: 5px;
}

.quick-contact ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.quick-contact ul > li a {
  display: block;
  padding: 3px;
  border: none;
  border-radius: 5px;
  text-align: center;
  text-decoration: none;
  font-size: 10px;
  font-weight: 700;
  line-height: 15px;
  color: #515151;
  max-width: 72px;
}

.quick-contact ul > li a i {
  display: block;
  width: 33px;
  height: 33px;
  margin: auto;
}

/* The SMS item is mobile only */
.quick-contact ul > li .chat_animation {
  display: none;
}

Icons are loaded as background images, one class each:

.quick-contact ul > li a i.ticon-zalo-circle2 {
  display: block;
  width: 36px;
  height: 36px;
  background: url(/images/icon-zalo.png) no-repeat;
  background-size: contain;
}

.quick-contact ul > li a i.ticon-messenger {
  display: block;
  width: 36px;
  height: 36px;
  background: url(/images/icon-messenger.png) no-repeat;
  background-size: contain;
}

My original version pointed the icons at an image host for convenience. In a real project, download them into your own folder: free image hosts can change their policy or delete files at any time, and each icon is another connection to a third party domain.

Turning it into a bottom bar on mobile

This is the interesting part. On a narrow screen the vertical block on the left covers content, so it becomes a full-width horizontal bar at the bottom:

@media only screen and (max-width: 600px) {
  .quick-contact {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 60px;
    padding: 5px;
    margin: 0;
    border-radius: 0;
    background: #fff;
    box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.3);
    z-index: 999;
  }

  .quick-contact li {
    float: left;
    width: 20%;
    height: 50px;
    list-style: none;
  }

  .quick-contact ul > li a {
    padding: 0;
    margin: 0 auto;
  }

  /* Show the call and SMS items that were hidden on desktop */
  .phone-mobile {
    display: block !important;
  }

  .quick-contact li .chat_animation {
    display: block !important;
  }

  /* The call button floats above the middle of the bar */
  .quick-contact li .button .phone_animation {
    position: absolute;
    top: -16px;
    left: 50%;
    transform: translate(-50%, 0);
    width: 50px;
    height: 50px;
    border: 2px solid #fff;
    border-radius: 100%;
    background: #6cb917;
    box-shadow: none;
  }
}

width: 20% divides the bar evenly among the 5 items shown on mobile. If you add or remove an item you have to update that number, or replace float with flexbox and let it divide itself:

.quick-contact ul {
  display: flex;
}
.quick-contact li {
  flex: 1;
}

The flex version is tidier and needs no manual percentages. The original used float because it had to support older browsers back then, which is no longer a concern.

Things worth improving

If I built this again from scratch, I would change a few things:

Add labels for screen readers. The <i> tags are just background images, so a screen reader user has no idea what they are. The “back to top” item currently has an icon and no text at all:

<a href="#" rel="nofollow" aria-label="Back to top">
  <i class="ticon-angle-up" aria-hidden="true"></i>
</a>

Leave room for the bottom bar. A fixed bar on mobile covers the end of the page. Add padding to the body so content is not hidden behind it:

@media only screen and (max-width: 600px) {
  body {
    padding-bottom: 60px;
  }
}

Use CSS variables for colours. If you plan to reuse this widget across projects, pulling the colours into variables saves a lot of find and replace:

.quick-contact {
  --qc-bg: #fff;
  --qc-text: #515151;
  --qc-accent: #6cb917;
}

No JavaScript, no plugin, and the whole thing weighs a few KB.