Web

Design & Implementation: lite.duckduckgo.com

8 min read

lite.duckduckgo.com (LDDG) is the ‘Lite’ experience of DuckDuckGo (DDG), a web search engine. Lite site variants typically forego all images and have very little-to-no JavaScript. LDDG manages to deliver a full search engine result page (SERP) consisting of approximately 30 results in just 10kB over the wire (compressed). How’s this possible?

I will be looking at the SERP for “example” in this article:

'Example' SERP on lite.duckduckgo.com.

lite.duckduckgo.com. is defined as a CNAME for duckduckgo.com.. Whenever making a request to LDDG, you are speaking to the same DDG frontend servers. The Host header is used to determine what application (LDDG or DDG) to serve you.

duckduckgo.com is hosted on Microsoft Azure. It leverages ECS routing to connect you to the datacenter closest to the DNS resolver you use.

European users may be connected to a server in Ireland:

An Irish IP owned by Microsoft Azure hosting duckduckgo.com

Whereas users connecting from the East Coast of the US might hit a server in Washington:

A US IP owned by Microsoft Azure hosting duckduckgo.com

DDG uses a wildcard certificate for *.duckduckgo.com signed by DigiCert with a 1-year expiration date. It offers HTTP2 (HTTP3 is not supported) and TLS 1.3 with perfect forward secrecy. TLS 1.2 is offered for compatibility. Older versions are not available for legacy clients, in order to protect against downgrade attacks. Strict HSTS is enabled via the HTTP header. Surprisingly, duckduckgo.com is not on the HSTS Preload List as of the time of writing.

LDDG advertises using nginx via the Server header. It offers modern Brotli compression.

A very strict CSP is set. Assets may only be loaded from duckduckgo.com, its subdomains, and its onion service, data and blob URLs are allowed for some assets (fonts and web workers).

content-security-policy: content-security-policy: default-src 'none' ; connect-src  https://duckduckgo.com https://*.duckduckgo.com https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ ; manifest-src  https://duckduckgo.com https://*.duckduckgo.com https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ ; media-src  https://duckduckgo.com https://*.duckduckgo.com https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ ; script-src blob:  https://duckduckgo.com https://*.duckduckgo.com https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ ; font-src data:  https://duckduckgo.com https://*.duckduckgo.com https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ ; img-src data:  https://duckduckgo.com https://*.duckduckgo.com https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ ; style-src  https://duckduckgo.com https://*.duckduckgo.com https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ ; object-src 'none' ; worker-src blob: ; child-src blob:  https://duckduckgo.com https://*.duckduckgo.com https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ ; frame-src blob:  https://duckduckgo.com https://*.duckduckgo.com https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/ ; frame-ancestors 'self' ; base-uri 'self' ; block-all-mixed-content ;

Assets are hosted on duckduckgo.com, and also advertise being served by nginx.

LDDG is a very simple HTML page. Its head provides an Open Search Description so users can easily use it as their preferred search engine.

A blast from the past: the page’s body uses &nbsp; for spacing and even uses a 1x1px transparent GIF for tracking. HTML tables are used to render the search results inside a <center> element. This makes the page usable even with CSS disabled.

A POST form to /lite is used for pagination and to submit a search with a different query, although query parameters may also be used to link to a specific SERP.

A tiny stylesheet spruces up the page a little. The font stack is 'Helvetica Neue','Segoe UI', Arial, sans-serif.

Oddly, some BEM-styled selectors are included in this file that are not used on the page. The .badge--yahoo selector references server-side template substitutiton that is not actually performed:

.badge--yahoo {
  background-image: url("<TMPL_VAR name="base_url_ext">/assets/attribution/yahoo.v103.png");
  background-size: 55px 13px;
  width: 55px;
  height: 13px;
}

This asset is available on duckduckgo.com. <TMPL_VAR> originates from the HTML::Template Perl library.

The selectors used by the page itself have arbitrary naming. Some selectors also target specific elements globally. This makes sense given the simple nature of the page, but wouldn’t scale to a larger site.

Chromium issues a warning for the incorrect formatting of the page’s viewport declaration. There should not be a semicolon at the end of its content:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=3.0, user-scalable=1;" />

Firefox warns that LDDG is rendered in “almost standards” mode (similar to quirks mode), due to the page’s HTML 4 doctype:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

The page itself does not log anything to the console. This is unsurprising: the page has no JavaScript.

Lighthouse reports excellent performance (a score of 99/100) and great Core Web Vitals scores. The main improvement that could be made to page speed would be to inline the stylesheet. The amount of CSS used is so small that perhaps even using inline styles would be a viable choice.

The tracking pixel is referenced for missing an alt attribute and explicit width/height. This doesn’t affect the experience however, as it is at the end of the document.

View the Lighthouse report here

axe reports several serious accessibility issues:

  • The <html> tag lacks the lang attribute.
  • The tracking pixel lacks an alt. Additionally, it should be hidden (aria-hidden).
  • The search form and does not have a label. This is also confusing for sighted users.
  • The <select> elements, used for region and recency filters, does not have a corresponding label. <option value selected>Label</option> is used for sighted users, but this is not semantic.
  • There is no landmark on the page, like a main element, that screen reader users could use to quickly skip to the search results. The role attribute could be used as an alternative to HTML5 elements if maximum compatibility is required.
  • The viewport definition sets maximum-scale=3.0 for no reason. This should be omitted.
  • There is no <h1> on the page. The DuckDuckGo text is styled as a heading but is not tagged as such.

There are no major issues with the tabbing order. The user must tab between search results. Arrow key navigation is supported only by duckduckgo.com through the use of scripting as a progressive enhancement.

lite.duckduckgo.com offers a fast, lightweight experience. Its servers are located globally to improve the end-user experience. Its implementation is extremely simple. The team went to painstaking lengths using HTML tables to ensure the page provides a usable experience even without CSS. The DuckDuckGo team should review and fix its accessibility issues.

  • The HTML5 doctype should be used
  • duckduckgo.com should be added to the HSTS Preload List
  • The page’s stylesheet should be inlined in the head, and unused classes should be removed
  • axe’s accessibility recommendations should be applied

Tags