惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
C
Check Point Blog
博客园 - Franky
月光博客
月光博客
T
Tenable Blog
博客园 - 聂微东
Cyberwarzone
Cyberwarzone
The GitHub Blog
The GitHub Blog
C
CERT Recently Published Vulnerability Notes
Scott Helme
Scott Helme
IT之家
IT之家
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CXSECURITY Database RSS Feed - CXSecurity.com
F
Full Disclosure
博客园 - 司徒正美
Project Zero
Project Zero
Y
Y Combinator Blog
A
Arctic Wolf
美团技术团队
博客园 - 叶小钗
S
Securelist
F
Fortinet All Blogs
T
Threatpost
T
Threat Research - Cisco Blogs
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
酷 壳 – CoolShell
酷 壳 – CoolShell
MyScale Blog
MyScale Blog
大猫的无限游戏
大猫的无限游戏
Recorded Future
Recorded Future
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
Schneier on Security
Apple Machine Learning Research
Apple Machine Learning Research
L
LangChain Blog
P
Privacy International News Feed
博客园_首页
S
SegmentFault 最新的问题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
腾讯CDC
P
Proofpoint News Feed
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
阮一峰的网络日志
阮一峰的网络日志
G
Google Developers Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
雷峰网
雷峰网
P
Proofpoint News Feed
Latest news
Latest news
G
GRAHAM CLULEY

CSS Wizardry

Front-End’s Missing Metric: The TBT Window Meet Your Users Where They Are with Obs.js Better Browser Caching with No-Vary-Search font-family Doesn’t Fall Back the Way You Think What Is CSS Containment and How Can I Use It? When All You Can Do Is All or Nothing, Do Nothing Obs.js: Context-Aware Web Performance for Everyone Low- and Mid-Tier Mobile for the Real World (2025) The Fastest Site in the Tour de France Making Sense of the Performance Extensibility API Why Do We Have a Cache-Control Request Header? HTML Is Not a Programming Language… Build for the Web, Build on the Web, Build with the Web Licensing Code on CSS Wizardry A Layered Approach to Speculation Rules Designing (and Evolving) a New Web Performance Score Core Web Vitals Colours The Ultimate Contract Templates for Tech Consultants: Protect Your Business and Get Paid Optimising for High Latency Environments Cache Grab: How Much Are You Leaving on the Table? blocking=render: Why would you do that?! Correctly Configure (Pre) Connections The Three Cs: 🤝 Concatenate, 🗜️ Compress, 🗳️ Cache What Is the Maximum max-age? How to Clear Cache and Cookies on a Customer’s Device The Ultimate Low-Quality Image Placeholder Technique Core Web Vitals for Search Engine Optimisation: What Do We Need to Know? The HTTP/1-liness of HTTP/2 In Defence of DOM­Content­Loaded Site-Speed Topography Remapped Why Not document.write()? Speeding Up Async Snippets Critical CSS? Not So Fast! Measure What You Impact, Not What You Influence Optimising Largest Contentful Paint Measuring Web Performance in Mobile Safari Site-Speed Topography Speed Up Google Fonts Real-World Effectiveness of Brotli Performance Budgets, Pragmatically Lazy Pre-Browsing with Prefetch Making Cloud.typography Fast(er) Time to First Byte: What It Is and How to Improve It Self-Host Your Static Assets Tips for Technical Interviews Cache-Control for Civilians Bandwidth or Latency: When to Optimise for Which ITCSS × Skillshare What If? CSS and Network Performance The Three Types of Performance Testing Getting to Know a Legacy Codebase Identifying, Auditing, and Discussing Third Parties My Digital Music Setup Measuring the Hard-to-Measure Finding Dead CSS The Fallacies of Distributed Computing (Applied to Front-End Performance) Ten Years Old Relative Requirements Airplanes and Ashtrays Performance and Resilience: Stress-Testing Third Parties Refactoring Tunnels Little Things I Like to Do with Git Writing Tidy Code Configuring Git and Vim Base64 Encoding & Performance, Part 2: Gathering Data Base64 Encoding & Performance, Part 1: What’s Up with Base64? Code Smells in CSS Revisited Typography for Developers Moving CSS Wizardry onto HTTPS and HTTP/2 Ack for CSS Developers A New Year, a New Focus Preparing Vim for Apple’s Touch Bar Choosing the Correct Average CSS Shorthand Syntax Considered an Anti-Pattern CSS Wizardry Newsletter Nesting Your BEM? Improving Perceived Performance with Multiple Background Images Continue Normalising Your CSS Pure CSS Content Filter Pragmatic, Practical, and Progressive Theming with Custom Properties Refactoring CSS: The Three I’s Speaker’s Checklist: Before and After Your Talk Improving Your CSS with Parker The Importance of !important: Forcing Immutability in CSS Mixins Better for Performance Managing Typography on Large Apps White October Events Workshop Partnership BEMIT: Taking the BEM Naming Convention a Step Further Travelling Like You Want to, When You Have To Contextual Styling: UI Components, Nesting, and Implementation Detail Subtleties with Self-Chained Classes Cyclomatic Complexity: Logic in CSS Immutable CSS Can CSS Be Too Modular? More Transparent UI Code with Namespaces When to use @extend; when to use a mixin The Specificity Graph CSS Wizardry Ltd.: Year 1 in review CSS Guidelines 2.0.0
Image Inconsistencies: How and When Browsers Download Images
Harry Roberts · 2018-06-12 · via CSS Wizardry

Written by on CSS Wizardry.

Table of Contents

Independent writing is brought to you via my wonderful Supporters.

  1. Background
  2. background-image
    1. What I Would Expect
    2. What Actually Happens
    3. Summary
    4. Verdict
  3. <img />
    1. What I Would Expect
    2. What Actually Happens
    3. Summary
    4. Verdict
  4. Key Takeaways
    1. The Facts
    2. How Might this Affect You?

This year, I’ve been working closely with the wonderful Coingaming team out in beautiful Tallinn. We’ve been working pretty hard on making their suite of online products much faster, and I’ve been the technical consultant leading the project. It’s been an incredibly fun and rewarding engagement, and we’ve made some real business- and customer-facing improvements. One of the key reasons I’ve found the project so fun is that it’s given me a real chance to get very forensic. Naturally, a team should always tackle the low-hanging fruit first, but once that’s done, you get to delve much deeper into the weeds. This blog post comes from there.

Background

In order to get better control over how a series of thumbnail images are displayed on the homepage of one of their products, the team opted to build them not as <img /> elements, but as CSS background-images: this allowed them to better size and position the images in their container, and, putting aside any semantic concerns, it made sense from a styling point of view. My only reservation was knowing that, because the images are defined in CSS rather than HTML, their outgoing requests won’t start until the browser has created the Render Tree: it’s not until all the CSS has been downloaded, parsed, and the CSSOM constructed that the browser actually knows This div with this class is currently visible on the page and its background is set to be this image: I’d better download it!.

The waterfall below shows the browser waiting for CSSOM completion before it dispatches any requests for any images—you can clearly see that the CSS needs to finish before any images start. This is down to the simple fact that the browser doesn’t know which (if any) images it will need until the CSSOM has been built:

Waterfall showing that background images cannot be downloaded until CSSOM has completed.

This is too late for such important content of theirs—users want to see the thumbnails as soon as possible.

By moving the images to <img /> elements (which is also semantically more appropriate), the browser can discover them far sooner—as they become exposed to the browser’s preload scanner—and dispatch their requests before (or in parallel to) CSSOM completion:

Waterfall showing how regular image elements can be downloaded independently of CSSOM construction.

This is stuff we already knew:

  1. Browsers can’t possibly download background-images until they’ve built the CSSOM.
  2. Browsers shouldn’t base—thus delay—the downloading of <img />s on CSSOM completion. More on this later…

Where it gets interesting is when I started to wonder how different browsers handle different types of image when they’re visible or not: an <img /> element with display: none; applied to it ideally wouldn’t get downloaded, but the only way the browser would know that the image is indeed hidden is if it waits for CSSOM completion, thus slowing down the default behavior of the <img />: what’s going to happen?


background-image

I will start with background-image as that’s what my client’s initial use case was. I feel like the behaviour for background-image should be the most predictable as there are certain impossibilities at play (e.g. we can’t download a background-image until we’ve built the CSSOM).

What I Would Expect

I have a couple of expectations (or hopes) that I predict:

  1. Browsers do not (can not) trigger a download for a background-image until it knows it needs it (i.e. until the CSSOM has been constructed).
  2. Browsers would not download background-image that is applied to an element that is hidden from view (e.g. display: none;).

What Actually Happens

Chrome (v67.0.3396.79)

Safari (v11.1 (13605.1.33.1.4))

Firefox (v60.0.1)

Opera (v53.0.2907.68)

Edge (v17.17134)

Summary

N.B. Yes or No represents factual information. and represent what I would consider good/expected and bad/unexpected behaviour, respectively.

  Chrome Safari Firefox Opera Edge
Block on CSSOM Yes ✓ Yes ✓ Yes ✓ Yes ✓ Yes ✓
Download if Invisible Yes ✗ No ✓ No ✓ Yes ✗ Yes ✗

Verdict

Firefox and Safari seem to have the most preferred behaviour here: they won’t download background-images that they know they won’t need.

Chrome, Opera, and Edge will all download background-images that are applied to invisible elements. This feels wasteful, but I suspect it is a preemptive optimisation to ensure that the image is on the client before the potential event that the element becomes visible. I feel that—if this is the case—this is an optimisation that should be left to the developer.


<img />

Next, let’s take a look at how browsers handle <img />s.

What I Would Expect

  1. Browsers will download <img /> completely independently of CSSOM construction. Blocking <img /> on CSSOM construction seems very inefficient, and would lead to delays in downloading content.
  2. Accordingly, browsers will download <img /> that end up being hidden from view, i.e. display: none;. If the browser starts downloading <img /> before CSSOM construction (as I expect) then it has no way of knowing yet whether that image is needed or not.

What Actually Happens

Chrome

Safari

Firefox

Opera

Edge

Summary

N.B. Yes or No represents factual information. and represent what I would consider good/expected and bad/unexpected behaviour, respectively.

  Chrome Safari Firefox Opera Edge
Block on CSSOM No ✓ No ✓ Yes ✗ No ✓ No ✓
Download if Invisible Yes ✓ Yes ✓ Yes ✗ Yes ✓ Yes ✓

Verdict

Firefox appears to block <img /> on CSSOM construction. This seems like a bad idea—no <img />s will begin downloading until Firefox has downloaded, parsed, and applied the CSS. This means that if you have blocking stylesheets, they’re blocking your <img />. This would be particularly troublesome if <img /> are key content (think Imgur, Flickr, etc.).

Firefox gets weirder still! It waits until it’s constructed the CSSOM before it fires off any <img /> requests, which means it knows if the <img /> will be visible or not, but if the <img /> is invisible, it will download it anyway. This is a double-hit: Firefox blocks <img /> on CSSOM construction yet still downloads <img /> that aren’t visible.


Key Takeaways

The Facts

  • Chrome, Opera, and Edge will download background-images that aren’t required for first render. This means that hidden DOM nodes that have a background-image applied to them will still have that background-image downloaded. Beware unexpected downloads.
  • Firefox will block <img /> downloads on CSSOM construction, meaning later-than-expected downloads. Beware delays.
  • Further, Firefox will still download the <img /> even if it wasn’t needed. Beware unexpected downloads.

How Might this Affect You?

If you’re a product that relies heavily on content imagery (e.g. Flickr, online publication, photographer) then Firefox will not download any of those images until it’s dealt with your CSS. You should look into preloading any key image content.

If you’re making heavy use of background images and, for whatever reason, are not showing all of them for first render, beware that some browsers will go ahead and download them anyway: you might want to look into better strategies for hidden content (e.g. removal from the DOM rather than display: none;).