<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sharing what we learn about the responsive web &#8211; Cloud Four</title>
	<atom:link href="https://cloudfour.com/thinks/feed/" rel="self" type="application/rss+xml" />
	<link>https://cloudfour.com</link>
	<description>Responsive web design and development, progressive web apps</description>
	<lastBuildDate>Thu, 16 Apr 2026 17:09:23 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
<site xmlns="com-wordpress:feed-additions:1">225560371</site>	<item>
		<title>Most Cookie Consent Banners Don&#8217;t Check for Compliance</title>
		<link>https://cloudfour.com/thinks/most-cookie-consent-banners-dont-check-for-compliance/</link>
					<comments>https://cloudfour.com/thinks/most-cookie-consent-banners-dont-check-for-compliance/#respond</comments>
		
		<dc:creator><![CDATA[Jason Grigsby]]></dc:creator>
		<pubDate>Thu, 16 Apr 2026 17:07:36 +0000</pubDate>
				<category><![CDATA[Privacy]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8553</guid>

					<description><![CDATA[Surprisingly, most cookie consent managers don't seem to check if websites are in compliance with CCPA and GPDR. Are you sure your website is in compliance?]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img fetchpriority="high" width="1024" height="576" src="https://cloudfour.com/wp-content/uploads/2026/04/cookie-compliance-r1-1024x576.png" alt="" class="wp-image-8554" srcset="https://cloudfour.com/wp-content/uploads/2026/04/cookie-compliance-r1-1024x576.png 1024w, https://cloudfour.com/wp-content/uploads/2026/04/cookie-compliance-r1-300x169.png 300w, https://cloudfour.com/wp-content/uploads/2026/04/cookie-compliance-r1-768x432.png 768w, https://cloudfour.com/wp-content/uploads/2026/04/cookie-compliance-r1-1536x864.png 1536w, https://cloudfour.com/wp-content/uploads/2026/04/cookie-compliance-r1-2048x1152.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>As I&#8217;ve had more opportunities to work with cookie consent managers, I&#8217;ve come to the surprising realization that most of them (all of them?) fail to track if websites are in compliance with various privacy laws.</p>



<p>One client we&#8217;ve been working with pays a lot of money for an enterprise-level cookie consent solution. Their cookie process is similar to what I&#8217;ve seen for other consent managers:</p>



<ul class="wp-block-list">
<li>The consent manager runs a scan across the client&#8217;s website to identify any cookies or other trackers.</li>



<li>The consent manager may provide a suggested category for any trackers that it recognizes.</li>



<li>The client has to verify that the suggested categorization is correct and categorize any cookies that the consent manager didn&#8217;t recognize.</li>



<li>There may be some additional work to make sure these categorizations are replicated in tag managers.</li>



<li>Once the categorization is complete, then the cookies <em>should</em> only be set when users provide the appropriate consent.</li>



<li>Periodically, the consent manager will scan the site to look for any new cookies or trackers. If any  are found, this process is repeated.</li>
</ul>



<p>The realization I&#8217;ve had is that the subsequent scans aren&#8217;t checking to verify that the cookies are being set correctly or not. Their primary purpose is to look for new cookies. That&#8217;s valuable, but it doesn&#8217;t ensure compliance.</p>



<p>Our client needed to be certain that non-required cookies weren&#8217;t getting set before consent was granted. I created a script that checks what trackers are set before and after consent. But in order to get this information from their enterprise solution, they had to request a special scan. </p>



<p>Even after requesting the special scan, our client only knew what had been set before consent. Not whether cookies were getting set correctly based on the categories users have consented to.</p>



<p>I wonder how many organizations think they&#8217;re in clear when it comes to CCPA or GPDR because they&#8217;ve implemented a cookie consent solution, but don&#8217;t realize that their solutions are never checking to make sure they are truly in compliance.</p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/most-cookie-consent-banners-dont-check-for-compliance/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8553</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/04/cookie-compliance-r1.png" width="550" height="309" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/04/cookie-compliance-r1.png" length="0" type="image/png" />	</item>
		<item>
		<title>Weight Loss and the World Wide Web</title>
		<link>https://cloudfour.com/thinks/weight-loss-and-the-world-wide-web/</link>
					<comments>https://cloudfour.com/thinks/weight-loss-and-the-world-wide-web/#respond</comments>
		
		<dc:creator><![CDATA[Jason Grigsby]]></dc:creator>
		<pubDate>Tue, 31 Mar 2026 17:03:16 +0000</pubDate>
				<category><![CDATA[Conferences]]></category>
		<category><![CDATA[Performance]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8530</guid>

					<description><![CDATA[On my successful journey with GLP-1 and my fruitless search to find a similar solution for the bloated mess the web has become.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img width="1024" height="576" src="https://cloudfour.com/wp-content/uploads/2026/03/20260327-weight-loss-perf-r2-1024x576.jpg" alt="" class="wp-image-8545" srcset="https://cloudfour.com/wp-content/uploads/2026/03/20260327-weight-loss-perf-r2-1024x576.jpg 1024w, https://cloudfour.com/wp-content/uploads/2026/03/20260327-weight-loss-perf-r2-300x169.jpg 300w, https://cloudfour.com/wp-content/uploads/2026/03/20260327-weight-loss-perf-r2-768x432.jpg 768w, https://cloudfour.com/wp-content/uploads/2026/03/20260327-weight-loss-perf-r2-1536x864.jpg 1536w, https://cloudfour.com/wp-content/uploads/2026/03/20260327-weight-loss-perf-r2.jpg 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Of all the talks I&#8217;ve given, none scared me more than my presentation at the <a href="https://perfnow.nl/2024/">2024 performance.now() conference</a>. The talk was ostensibly about third-party scripts and web performance, but it also touched on a topic embarrassing to me—my weight—and equated it to what I was observing on the web.</p>



<p>Two recent events reminded me of this talk, how much has changed for me since then because of GLP-1, and how the same can’t be said for the web.</p>



<h2 class="wp-block-heading"><strong>Struggling to get healthier</strong></h2>



<p>I was in a strange place in Fall of 2024. We had spent three and a half years taking care of my father before he passed in October 2023. He had suffered a stroke right before COVID that left him bedridden with a tracheostomy. A respiratory pandemic is difficult enough to survive without a direct path to your lungs.</p>



<p>To keep him safe, we took him into our home and became his nurses, respiratory therapists, PTs—anything necessary to keep him alive.&nbsp;</p>



<figure class="wp-block-image size-full"><img width="886" height="886" src="https://cloudfour.com/wp-content/uploads/2026/03/image.jpeg" alt="My father is asleep in a hospital bed in our house. In the foreground, a bag of food hangs off a pole where a machine slowly provided food via a  gastrostomy tube. In the background, a ventilator acts as a BiPap connected to his trach at night. A large leprechaun decoration hangs on the wall. My dad once joked the leprechaun was his childhood friend Gary and after that Gary stayed on the wall year round." class="wp-image-8534" srcset="https://cloudfour.com/wp-content/uploads/2026/03/image.jpeg 886w, https://cloudfour.com/wp-content/uploads/2026/03/image-300x300.jpeg 300w, https://cloudfour.com/wp-content/uploads/2026/03/image-150x150.jpeg 150w, https://cloudfour.com/wp-content/uploads/2026/03/image-768x768.jpeg 768w" sizes="(max-width: 886px) 100vw, 886px" /><figcaption class="wp-element-caption">This was the view from my bed every night for three and half years. I slept downstairs so I could keep an eye on my father and could assist him if his oxygen dropped suddenly.</figcaption></figure>



<p>Taking care of him was all-consuming. As a result, our own health suffered. I gained a lot of weight and had a couple of health scares that sent me to the ER. I was pre-diabetic and while my bloodwork wasn’t dangerous yet, it was heading the wrong direction.</p>



<p>After my father passed, I was determined to lose weight and get into shape. I didn’t want to put the same burden on our kids that my father had on us.</p>



<p>So I set up a home gym in the space that had previously been his hospital room. I started rowing and lifting weights daily for the first time in my life. I purchased an underdesk treadmill so I could exercise while working.</p>



<figure class="wp-block-image size-full"><img width="1024" height="768" src="https://cloudfour.com/wp-content/uploads/2026/03/image-1.jpeg" alt="A photo of our home gym. On the wall is a Tonal system for weight lifting. It is stored away at the moment and looks like a vertical TV. Hanging to the left of the Tonal from the bottom of a shelf are its accessories: a rope, two handles, and bar. To the right of the Tonal is an actual TV. Below it is a Hydrow rowing machine. Around the room are various other workout accessories like dumbbells. The closet doors have mirrors on them." class="wp-image-8535" srcset="https://cloudfour.com/wp-content/uploads/2026/03/image-1.jpeg 1024w, https://cloudfour.com/wp-content/uploads/2026/03/image-1-300x225.jpeg 300w, https://cloudfour.com/wp-content/uploads/2026/03/image-1-768x576.jpeg 768w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Our home gym occupies the same space where my father&#8217;s hospital bed once was. I often think about him while I work out.</figcaption></figure>



<p>I saw some improvements. I was stronger than I had ever been and had lost some weight, but I had plateaued. I wasn’t losing weight any more. I felt stuck.</p>



<h2 class="wp-block-heading"><strong>Our clients were stuck too</strong></h2>



<p>Around this same time, I was conducting performance audits for some of our clients. I love helping organizations make their websites run faster so working on performance audits is usually one of my favorite tasks. But in these cases, the audits were frustrating.</p>



<p>Like the vast majority of websites we see in the wild, the biggest performance problems for our clients were due to third-party scripts. The good news was that I could identify which scripts caused the most issues. I could even show how much faster their site would be if they removed the scripts.</p>



<p>The bad news was that even if they wanted to, our clients couldn’t remove the scripts. In one case, the client was using <a href="https://www.bolt.com/checkout">Bolt</a> for their cart and checkout. Bolt was a massive React app that weighed in at nearly 1MB. It slowed down the most critical parts of an ecommerce funnel. But <a href="https://cloudfour.com/thinks/who-can-you-trust-with-your-online-business/#call-2-the-ecommerce-company">they couldn’t remove it</a> without breaking core functionality.</p>



<h2 class="wp-block-heading"><strong>Ozempic and other GLP-1s</strong></h2>



<p>It didn’t seem to matter how much I worked out. I wasn’t losing weight. So I started researching Ozempic and other GLP-1s.</p>



<p>I was intrigued by the way <a href="https://chriscoyier.net/2023/03/09/semaglutide/">Chris Coyier</a> and Paul Ford described their own experiences. Paul Ford <a href="https://www.wired.com/story/new-drug-switched-off-appetite-mounjaro/">wrote</a>:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Where before my brain had been screaming, screaming, at air-raid volume—there was sudden silence. It was confusing. Would it last?</p>



<p>I went alone that night to a Chinese restaurant, the old-school kind with tables, and ordered General Tso’s. I ate the broccoli, a few pieces of chicken, and thought: too gloopy. I left it unfinished, went home in confusion, a different kind of sleepwalker. I passed bodegas and shrugged. At an office I observed the stack of candies and treats with no particular interest.</p>



<p>Decades of struggle—poof.&nbsp;</p>
</blockquote>



<p>Before I started using GLP-1, it had already changed me. The success of these drugs made me reassess my relationship to weight loss. If the food noise in my head could be tamed with medication, then perhaps my weight wasn’t a personal failing.&nbsp;</p>



<p>I wasn’t weak. I was just wired in a way that caused my brain to think I was hungry when I wasn’t. And I could be rewired.</p>



<h2 class="wp-block-heading"><strong>What about a GLP-1 for the web?</strong></h2>



<p>As preparation for my talk heated up, I found myself researching third-party scripts during the day and GLP-1s at night. It’s no surprise I started to see parallels between them.</p>



<figure class="wp-block-image size-large"><img width="1024" height="379" src="https://cloudfour.com/wp-content/uploads/2026/03/image-4-1024x379.png" alt="A screenshot of a Jeffrey Zeldman tweet. In the tweet, he quotes me at An Event Apart Orlando saying, &quot;We've made the internet in our own image. Which, in the United States, means obese.&quot;" class="wp-image-8542" srcset="https://cloudfour.com/wp-content/uploads/2026/03/image-4-1024x379.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/image-4-300x111.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/image-4-768x284.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/image-4.png 1190w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">This isn&#8217;t the first time I&#8217;ve drawn a parallel between web performance and unhealthy weight. It used to be a punchline in my talks about the mobile web.</figcaption></figure>



<p>Most website owners know how important performance is for user experience and how it impacts conversions and revenue. They want a fast site.&nbsp;</p>



<p>And yet websites continue to grow in size. Even ecommerce sites which have a strong financial motivation to fix performance issues get larger every year on average.</p>



<p>I knew I needed help to get unstuck. Maybe my clients did too?</p>



<p>I started looking for something akin to a GLP-1 for the web. I knew it wouldn’t solve every problem, but maybe a little boost would help. Was there some way we could rewire the web like I hoped GLP-1 would rewire my brain?</p>



<p>This became a focal point of my research. I looked into <a href="https://partytown.qwik.dev/">Partytown</a> which tries to move third-party scripts off the main thread and onto a web worker where they will have less impact on the user. I explored <a href="https://www.cloudflare.com/application-services/products/zaraz/">Cloudflare’s Zaraz</a> product which attempts something similar using Edge Workers. I revisited <a href="https://developers.google.com/tag-platform/tag-manager/server-side">server-side Google Tag Manager</a> for the umpteenth time hoping that this time it seemed more likely to work for our clients.</p>



<figure class="wp-block-image size-large is-style-outlined"><img width="1024" height="588" src="https://cloudfour.com/wp-content/uploads/2026/03/image-2-1024x588.png" alt="A diagram from the Partytown website that visualizes how it works. On the left in an image titled &quot;Without Partytown,&quot; it shows a funnel labeled main thread with orange and blue circles in it. The blue circles represent your code and the orange third-party scripts. Both are competing to get through the funnel.

On the right is a diagram entitled &quot;With Partytown.&quot; This diagram has two funnels. One is labeled main thread and only has blue circles representing your code. The second funnel is labeled worker thread where all of the third-party, orange circles are now found." class="wp-image-8533" srcset="https://cloudfour.com/wp-content/uploads/2026/03/image-2-1024x588.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/image-2-300x172.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/image-2-768x441.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/image-2-1536x882.png 1536w, https://cloudfour.com/wp-content/uploads/2026/03/image-2.png 1957w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Partytown has been a bit of an obsession for me. It makes so much sense to move JavaScript off the main thread, and it worked well on one project…until it didn&#8217;t and the client removed it.</figcaption></figure>



<p>But every one of these solutions had significant drawbacks. They are all difficult to implement. I wasn’t certain how I could tell if third-party scripts were still working, especially when we don’t usually have access to the dashboards for these services.</p>



<p>That’s not to say that some people aren’t having success with them. Julian Jandl shared <a href="https://www.youtube.com/watch?v=rFrqJQshh6M&amp;list=PLjnstNlepBvNBmLtuc8GHaVfjFUdI36Cq&amp;index=8">how they’ve been using Partytown successfully</a> at performance.sync() 2025. I think it is easier for internal teams to experiment with solutions like this than it is for our clients to sign up for something unproven.</p>



<p>If I was working on the talk today, I’m sure someone in the audience would ask if AI could help. If AI will cure cancer, surely it can solve web site bloat.</p>



<p>Unfortunately, most AI-generated websites seem to have performance problems. Tim Kadlec points out that <a href="https://bsky.app/profile/did:plc:vkym4t5ccdd3tidm32pkz2ke/post/3mhxwzlsqhc2b">JavaScript bytes on the web have exploded since May 2025</a>—the month when Claude Code, Github Copilot Coding Agent, and Cursor AI agents launched.</p>



<figure class="wp-block-image size-large"><a href="https://bsky.app/profile/did:plc:vkym4t5ccdd3tidm32pkz2ke/post/3mhxwzlsqhc2b"><img width="1024" height="399" src="https://cloudfour.com/wp-content/uploads/2026/03/image-1024x399.png" alt="Tim Kadlec's Blusky post says, &quot;p75 and p90 JavaScript bytes on the web have exploded since May, 2025—easily the largest 10 month period based on HTTP Archive data since 2023. 

The long-tail is getting worse, very quickly.

Gemini, what happened in May 2025?&quot;" class="wp-image-8531" srcset="https://cloudfour.com/wp-content/uploads/2026/03/image-1024x399.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/image-300x117.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/image-768x300.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/image.png 1174w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p>I suppose it doesn’t have to be that way. In theory, you can add enough context or constraints to get a performant experience out of AI, but that would require people to prioritize it. It doesn’t happen by default. So I don’t see AI solving the web&#8217;s performance problems (or cancer) any time soon.</p>



<h2 class="wp-block-heading"><strong>Video of my presentation</strong></h2>



<p>While I didn’t find a GLP-1 for the web, I’m still proud of the talk. There are many practical suggestions on how to analyze and manage third-party scripts.&nbsp;</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Third Party Woes | Jason Grigsby | performance.now() 2024" width="500" height="281" src="https://www.youtube.com/embed/wI5frInvfQM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<p>I recommend watching the talk, but I’ll admit I have a hard time doing so. I was going to send it to a client last week and was shocked at how big I look in the video.</p>



<h2 class="wp-block-heading"><strong>My Tirzepatide journey</strong></h2>



<p>I nearly started GLP-1 before the performance.now() conference, but I was worried about potential side effects before the trip. I didn’t want indigestion during the conference or after it when my family was meeting me for a vacation.</p>



<p>After we returned home, the holidays took precedence. In early 2025, I read about the FDA <a href="https://thehill.com/policy/healthcare/5158023-ozempic-and-wegovy-officially-moved-off-fdas-drug-shortage-list/">removing some GLP-1s from the shortage list</a> which meant compounding pharmacies could no longer make it. Compounding pharmacies were providing affordable alternatives. I knew I couldn’t afford the full price, and my insurance wasn’t going to cover it.</p>



<p>So I gave up for a bit until a friend who I hadn’t seen in a few months visited. I was stunned by his transformation. He was on Tirzepatide (a different GLP-1) and looked like an entirely different person.</p>



<figure class="wp-block-image size-large"><img width="1024" height="832" src="https://cloudfour.com/wp-content/uploads/2026/03/7062B6D6-668F-4B7D-A94F-C086885499EC_1_201_a-1024x832.jpeg" alt="A line graph from the health app shows my weight loss over the last several months. The graph shows a gentle increase in April and May of last year before a big drop starts in June." class="wp-image-8541" srcset="https://cloudfour.com/wp-content/uploads/2026/03/7062B6D6-668F-4B7D-A94F-C086885499EC_1_201_a-1024x832.jpeg 1024w, https://cloudfour.com/wp-content/uploads/2026/03/7062B6D6-668F-4B7D-A94F-C086885499EC_1_201_a-300x244.jpeg 300w, https://cloudfour.com/wp-content/uploads/2026/03/7062B6D6-668F-4B7D-A94F-C086885499EC_1_201_a-768x624.jpeg 768w, https://cloudfour.com/wp-content/uploads/2026/03/7062B6D6-668F-4B7D-A94F-C086885499EC_1_201_a.jpeg 1057w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Can you tell from this graph when I started taking Tirzepatide?</figcaption></figure>



<p>His experience inspired me to give it another try. I took my first shot of Tirzepatide on June 27, 2025. I still have more to go, but I’ve lost 50 pounds so far. I’m at the lowest weight since college. I can now see the evidence of my daily workouts. And most importantly, my blood work is trending in the right direction.</p>



<figure class="wp-block-image size-full"><img width="768" height="1024" src="https://cloudfour.com/wp-content/uploads/2026/03/image-3.jpeg" alt="I photo of me taken in a mirror. I'm wearing jeans and a black Star Wars shirt. I'm not thin, but I'm much healthier than I was at performance.now() in 2024." class="wp-image-8537" srcset="https://cloudfour.com/wp-content/uploads/2026/03/image-3.jpeg 768w, https://cloudfour.com/wp-content/uploads/2026/03/image-3-225x300.jpeg 225w" sizes="(max-width: 768px) 100vw, 768px" /><figcaption class="wp-element-caption">I can&#8217;t remember the last time I took a photo of myself that I liked, but I don&#8217;t hate this recent one.</figcaption></figure>



<h2 class="wp-block-heading"><strong>The 49MB Web Page</strong></h2>



<p>Unfortunately, the story for the web over the same period hasn’t been great. One of the triggers for revisiting my presentation was this excellent article by Shubham Bose examining a <a href="https://thatshubham.com/blog/news-audit">49MB New York Times article</a>.</p>



<figure class="wp-block-image size-large"><img width="1024" height="576" src="https://cloudfour.com/wp-content/uploads/2026/03/image-3-1024x576.png" alt="A screenshot of Shubham Bose's article entitled &quot;The 49MB Web Page.&quot; " class="wp-image-8538" srcset="https://cloudfour.com/wp-content/uploads/2026/03/image-3-1024x576.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/image-3-300x169.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/image-3-768x432.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/image-3-1536x864.png 1536w, https://cloudfour.com/wp-content/uploads/2026/03/image-3.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Bose points out all of the privacy and user hostile code being used on the web these days. Most of this code comes from third-party scripts.</p>



<p>And maybe it’s a bit of silly numerology, but I couldn’t help but feel some kinship to this random NYT article. The page weighs 49MB. I’ve lost 50 pounds.</p>



<p>I wish I could share some of my Tirzepatide with these pages.</p>



<h2 class="wp-block-heading"><strong>Open for discussion</strong></h2>



<p>I like helping people build faster websites, but I can only help so many clients at a time. It’s a drop in the bucket compared to the direction the web is headed. It feels as futile as dieting.</p>



<p>The main purpose for my talk was to spur discussion in the web performance community because I believe only collective action on third-party scripts can make a difference. I don’t know if we will be able to find some miracle GLP-1-like solution for third-parties. But maybe we can make it easier for people to learn which third-party scripts are better from a performance standpoint. That would be a good start.</p>



<p>In a similar vein, I’d like this article to be the starting point for discussion. If you want to brainstorm ways to handle third-parties and make the web faster, I’d love to hear about it—particularly if you’ve successfully used PartyTown, Zaraz, or server-side GTM.&nbsp;</p>



<p>I’m also open to talking about weight loss and my experience with Tirzepatide. I’m keenly aware of how difficult it can be to talk about these things. I’ve been too embarrassed to do so for years. But Tirzepatide has made a huge difference for me so I’m happy to share what I’ve learned.</p>



<p>So I’m open for discussion. You can ask me anything. You can reach out publicly or privately. I’m happy to talk about either topic or anything else that may be on your mind. We&#8217;re all in this together.</p>



<p>P.S. <a href="https://cloudfour.com/thinks/more-projects-please/">We&#8217;re looking for projects</a>. Please spread the word.</p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/weight-loss-and-the-world-wide-web/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8530</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/03/20260327-weight-loss-perf-r2.jpg" width="550" height="309" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/03/20260327-weight-loss-perf-r2.jpg" length="0" type="image/jpg" />	</item>
		<item>
		<title>More Projects Please</title>
		<link>https://cloudfour.com/thinks/more-projects-please/</link>
					<comments>https://cloudfour.com/thinks/more-projects-please/#respond</comments>
		
		<dc:creator><![CDATA[Tyler Sticka]]></dc:creator>
		<pubDate>Mon, 30 Mar 2026 15:38:36 +0000</pubDate>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Process]]></category>
		<category><![CDATA[UX]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8529</guid>

					<description><![CDATA[We’re actively seeking new UX design, UI design or hybrid creative/development challenges to solve.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img width="1920" height="960" src="https://cloudfour.com/wp-content/uploads/2026/03/cloud-four-and-you-r3-wide.png" alt="Cloud Four and you" class="wp-image-8544" srcset="https://cloudfour.com/wp-content/uploads/2026/03/cloud-four-and-you-r3-wide.png 1920w, https://cloudfour.com/wp-content/uploads/2026/03/cloud-four-and-you-r3-wide-300x150.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/cloud-four-and-you-r3-wide-1024x512.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/cloud-four-and-you-r3-wide-768x384.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/cloud-four-and-you-r3-wide-1536x768.png 1536w" sizes="(max-width: 1920px) 100vw, 1920px" /></figure>



<p>I&#8217;ll cut to the chase: Our calendar is light, and <a href="https://cloudfour.com/and-you/">we need more projects</a>. Especially projects with a <strong>UX design</strong>, <strong>UI design</strong> or <strong>hybrid creative/development</strong> focus.</p>



<p><strong>Small projects?</strong> No prob, we&#8217;ve got individual high-velocity contributors to spare, ready to slot in at any project stage.</p>



<p><strong>Large projects?</strong> Bring it on: Our unique approach scales well to big problems, like <a href="https://cloudfour.com/does/legacy-app-modernization/" data-type="link" data-id="https://cloudfour.com/does/legacy-app-modernization/">modernizing legacy applications</a> or building up <a href="https://cloudfour.com/made/baptist-health/">multi-brand design systems</a>. (Once you&#8217;ve made <a href="https://cloudfour.com/made/walmart/">Walmart&#8217;s cart and checkout responsive</a>, you can do anything!)</p>



<p>(Already know us? <a href="#how-to-help" data-type="internal" data-id="#how-to-help">Skip to ways you can help</a>)</p>



<h2 class="wp-block-heading">Why Cloud Four?</h2>



<ul class="wp-block-list">
<li>Your audience deserves better than <em>just another</em> sluggish, inaccessible, generic web experience.</li>



<li>Our fast-paced, collaborative process keeps your team engaged and your goals in focus.</li>



<li>Interactive, browser-based deliverables remove guesswork from the review process while streamlining implementation.</li>



<li>You&#8217;ll support a small, independent company that&#8217;s served customers for almost 20 years while sharing more than 25 talks, 80 code repositories and 500 (!!) articles for free with their community.</li>
</ul>



<h2 class="wp-block-heading">What clients say</h2>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Cloud Four really dug in to understand what our customers needed and how our business worked. We chose Cloud Four for their web expertise, but <a href="https://cloudfour.com/made/imagequix/">what they delivered</a> would be world-class on any platform. I’m so proud of what we accomplished together.</p>
</blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Cloud Four’s process stands out for being so transparent, iterative and collaborative. They listened carefully to our goals, asked tough but important questions, and encouraged contributions from everyone. I’m amazed by how much <a href="https://cloudfour.com/made/baptist-health/">our web experiences transformed with their guidance</a>.</p>
</blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Cloud Four not only massively simplified our <a href="https://cloudfour.com/does/ecommerce/">purchasing flow</a> but also prototyped a foundation for our future plans. On top of that, they were also an absolute pleasure to work with. Professional, thoughtful, and most importantly fun.</p>
</blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><a href="https://cloudfour.com/made/cloudinary-interactive-demo/">The API Explorer demo</a> has been a big help in explaining our APIs to developers. It increased engagement over 400% and improved the quality of our conversions.</p>
</blockquote>



<h2 class="wp-block-heading">How to help</h2>



<p><strong>If you have (or <em>may</em> have) a project</strong>, get in touch via <a href="https://cloudfour.com/and-you/">our contact form, email or phone</a>.</p>



<p><strong>If you have a boss or hiring manager in charge of contracting design resources</strong>, recommend us to them, share this post, or <a href="https://cloudfour.com/and-you/">reach out</a> to make that connection directly.</p>



<p><strong>Share this post</strong> (or <a href="https://cloudfour.com/thinks/">any article</a> you find more relevant) with friends, family, forums, work chats, or social connections who might benefit from (or amplify) our services.</p>



<p>It&#8217;s thanks to our amazing clients we&#8217;ve been able to ship so many exceptional experiences over the past 19 years, continually sharing what we learn along the way. I hope you&#8217;ll be part of that journey soon!</p>



<p></p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/more-projects-please/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8529</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/03/cloud-four-and-you-r3.png" width="550" height="309" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/03/cloud-four-and-you-r3.png" length="0" type="image/png" />	</item>
		<item>
		<title>GPC Opt Out: UX Fails or Malicious Compliance?</title>
		<link>https://cloudfour.com/thinks/gpc-opt-out-ux-fails-or-malicious-compliance/</link>
					<comments>https://cloudfour.com/thinks/gpc-opt-out-ux-fails-or-malicious-compliance/#respond</comments>
		
		<dc:creator><![CDATA[Jason Grigsby]]></dc:creator>
		<pubDate>Mon, 23 Mar 2026 17:11:18 +0000</pubDate>
				<category><![CDATA[Essentials]]></category>
		<category><![CDATA[Privacy]]></category>
		<category><![CDATA[UX]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8513</guid>

					<description><![CDATA[As of Jan 1, the CCPA requires websites to confirm they are honoring Global Privacy Control (GPC) opt outs. Why are so many cookie banners complying with the new rule in ways certain to confuse users?]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img width="1600" height="900" src="https://cloudfour.com/wp-content/uploads/2026/03/gpc-opt-out-feature-r1.png" alt="" class="wp-image-8522" srcset="https://cloudfour.com/wp-content/uploads/2026/03/gpc-opt-out-feature-r1.png 1600w, https://cloudfour.com/wp-content/uploads/2026/03/gpc-opt-out-feature-r1-300x169.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/gpc-opt-out-feature-r1-1024x576.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/gpc-opt-out-feature-r1-768x432.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/gpc-opt-out-feature-r1-1536x864.png 1536w" sizes="(max-width: 1600px) 100vw, 1600px" /></figure>



<p>Starting on January 1, the California Consumer Privacy Act (CCPA) requires that websites provide confirmation that they have honored a user&#8217;s Global Privacy Control (GPC) opt out. Unfortunately, many cookie consent banners are doing this in the most confusing way possible and making me wonder if they are doing it intentionally or not.</p>



<h2 class="wp-block-heading">What is Global Privacy Control?</h2>



<p>Global Privacy Control is a <a href="https://w3c.github.io/gpc/">web standard</a> that allows users to tell websites that they wish to opt out of having their information tracked or sold. In theory, if you have set Global Privacy Control, you shouldn&#8217;t see any cookie consent banners.</p>



<p>Global Privacy Control works behind the scenes by setting two values. One is an HTTP Header, <code>Sec-GPC: 1</code>, that is sent by the browser with every request to a server. The second value makes sure GPC is available to JavaScript by setting <code>navigator.globalPrivacyControl</code>&nbsp;property to&nbsp;<code>true</code>. </p>



<p>Some browsers—Firefox, DuckDuckGo, and Brave among them—implement GPC support by default. For other browsers, you can install extensions like the Electronic Freedom Foundation&#8217;s <a href="https://privacybadger.org/" data-type="link" data-id="https://privacybadger.org/">Privacy Badger</a>. If you want to test to see if your browser is sending GPC correctly, you can test it on the <a href="https://globalprivacycontrol.org/">Global Privacy Control informational site</a>.</p>



<figure class="wp-block-image size-full"><img width="1400" height="788" src="https://cloudfour.com/wp-content/uploads/2026/03/gpc-website.jpg" alt="" class="wp-image-8514" srcset="https://cloudfour.com/wp-content/uploads/2026/03/gpc-website.jpg 1400w, https://cloudfour.com/wp-content/uploads/2026/03/gpc-website-300x169.jpg 300w, https://cloudfour.com/wp-content/uploads/2026/03/gpc-website-1024x576.jpg 1024w, https://cloudfour.com/wp-content/uploads/2026/03/gpc-website-768x432.jpg 768w" sizes="(max-width: 1400px) 100vw, 1400px" /><figcaption class="wp-element-caption">The Global Privacy Control informational website displays a banner at the top of the page to let you know if your browser sent a GPC signal or not.</figcaption></figure>



<h2 class="wp-block-heading">What happened to Do Not Track?</h2>



<p>Some of you may be wondering how Global Privacy Controls differ from an earlier solution called <a href="https://en.wikipedia.org/wiki/Do_Not_Track">Do Not Track</a>. While Do Not Track also used HTTP Headers to opt out of tracking, it wasn&#8217;t an official standard, and never gained traction with website owners. In 2019, the working group behind Do Not Track disbanded, and browsers started removing support for it.</p>



<p>The biggest difference between Do Not Track and GPC is that GPC has been codified in law. <a href="https://cookie-script.com/privacy-laws/global-privacy-control-vs-do-not-track" data-type="link" data-id="https://cookie-script.com/privacy-laws/global-privacy-control-vs-do-not-track">Eleven states</a> require businesses to honor GPC opt outs. The EU&#8217;s General Data Protection Regulation (GDPR) was written before GPC was created, but it likely that GPC still applies under GDPR. According to <a href="https://cookie-script.com/privacy-laws/global-privacy-control-vs-do-not-track">CookieScript</a>, &#8220;While not explicitly mentioned in the GDPR regulation, the principles of &#8216;Privacy by Design&#8217; and &#8216;Ease of Withdrawal&#8217; make GPC signal a requirement to honor user opt-out choices.&#8221;</p>



<h2 class="wp-block-heading">UX fails or malicious compliance?</h2>



<p>All of this brings me back to California&#8217;s new GPC confirmation rule and the odd way that cookie consent solutions have implemented it. Digital compliance vendor Clym <a href="https://www.clym.io/blog/ccpa-selling-and-sharing-what-counts-as-a-sale-or-share">describes the new rule</a> thusly:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Starting in 2026, it is no longer sufficient to simply process an opt-out silently. If you receive an opt-out signal (like the Global Privacy Control), you must explicitly&nbsp;<strong>display a confirmation</strong>&nbsp;to the user.</p>



<ul class="wp-block-list">
<li><strong>Requirement:</strong>&nbsp;You may need to display a message like &#8220;Opt-Out Request Honored&#8221; or show a toggle in the user’s privacy settings indicating they have opted out.</li>



<li>This allows consumers to know that their automated browser signals are working.</li>
</ul>
</blockquote>



<p>Because I have GPC turned on in my browser, I began to see these confirmations. Unfortunately, it is often not clear what I should do with the information. For example, this is what I saw on a recent website using OneTrust for cookie management:</p>



<figure class="wp-block-image size-full is-style-outlined"><img width="912" height="640" src="https://cloudfour.com/wp-content/uploads/2026/03/onetrust-opt-out-honored-2.png" alt="" class="wp-image-8525" srcset="https://cloudfour.com/wp-content/uploads/2026/03/onetrust-opt-out-honored-2.png 912w, https://cloudfour.com/wp-content/uploads/2026/03/onetrust-opt-out-honored-2-300x211.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/onetrust-opt-out-honored-2-768x539.png 768w" sizes="(max-width: 912px) 100vw, 912px" /></figure>



<p>It&#8217;s nice to see confirmation that my opt out preference has been honored, but what am I supposed to do now?</p>



<p>There is a big button that says, &#8220;Accept All Cookies&#8221; that appears to be my main option. If I click on it, will the site still honor my opt out? Or will clicking on the button override GPC?</p>



<p>I decided to give it try, and as expected, clicking the only button available to me overrode my opt out.</p>



<figure class="wp-block-image size-large is-style-outlined"><img width="579" height="1024" src="https://cloudfour.com/wp-content/uploads/2026/03/onetrust-privacy-center-1-579x1024.png" alt="OneTrust's Privacy Preference Center panel. At the top, the same green box from earlier says, &quot;Your Opt out Preference Signal is Honored.&quot; At the bottom, every cookie consent category is turned on." class="wp-image-8518" srcset="https://cloudfour.com/wp-content/uploads/2026/03/onetrust-privacy-center-1-579x1024.png 579w, https://cloudfour.com/wp-content/uploads/2026/03/onetrust-privacy-center-1-170x300.png 170w, https://cloudfour.com/wp-content/uploads/2026/03/onetrust-privacy-center-1-768x1359.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/onetrust-privacy-center-1.png 837w" sizes="(max-width: 579px) 100vw, 579px" /></figure>



<p>I find this preferences panel hilarious. It says it has honored my opt out, but every bit of tracking has been turned on. I tested a few other cookie consent options and found similar interfaces where you&#8217;re informed that your opt-out has been honored, but you&#8217;re still forced to make a choice about what cookies you will allow.</p>



<figure class="wp-block-image size-full"><img width="872" height="554" src="https://cloudfour.com/wp-content/uploads/2026/03/osano-banner-2.png" alt="" class="wp-image-8521" srcset="https://cloudfour.com/wp-content/uploads/2026/03/osano-banner-2.png 872w, https://cloudfour.com/wp-content/uploads/2026/03/osano-banner-2-300x191.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/osano-banner-2-768x488.png 768w" sizes="(max-width: 872px) 100vw, 872px" /><figcaption class="wp-element-caption">In this example from Osano, the Opt-Out Signal is Honored, but you still have to choose to between &#8220;Accept,&#8221; &#8220;Deny Non-Essential,&#8221; and &#8220;Manage Preferences&#8221; buttons.</figcaption></figure>



<p>I know that for any of these banners, I can click on the cookies settings link to adjust my preferences, but isn&#8217;t the whole point of the GPC opt out to streamline the process so users don&#8217;t have to manually opt out?</p>



<p>By contrast, the best implementation I&#8217;ve seen was a small notification that my opt-out had been honored. That&#8217;s it. No further action required. I believe this is what California was hoping for when it added this new requirement.</p>



<p>It seems the new rule has surprised cookie consent managers. In my testing, many of them do not yet honor the notification requirement even if they honor GPC behind the scenes. So perhaps these broken and confusing user experiences are because notifications are being quickly grafted onto existing applications.</p>



<p>However, when I see that the service is aware that I&#8217;ve opted out, and the only button it provides is one to accept all cookies, I find myself wondering if it is intentional. I know <a href="https://en.wikipedia.org/wiki/Hanlon's_razor">Hanlon&#8217;s Razor</a> says we shouldn&#8217;t immediately ascribe situations like this to malice so I&#8217;m hopeful that over time cookie consent banners will do a better job of honoring GPC opt outs.</p>



<p>If you&#8217;re interested in learning more about privacy and cookies, check out my recent two-part series on <a href="https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-1-overview/" data-type="link" data-id="https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-1-overview/">cookie consent management in 2026</a>.</p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/gpc-opt-out-ux-fails-or-malicious-compliance/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8513</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/03/gpc-opt-out-feature-r1.png" width="550" height="309" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/03/gpc-opt-out-feature-r1.png" length="0" type="image/png" />	</item>
		<item>
		<title>Cookie Consent Management in 2026, Part 2: Technical Tips</title>
		<link>https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-2-technical-tips/</link>
					<comments>https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-2-technical-tips/#respond</comments>
		
		<dc:creator><![CDATA[Jason Grigsby]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 16:35:34 +0000</pubDate>
				<category><![CDATA[Essentials]]></category>
		<category><![CDATA[Privacy]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8509</guid>

					<description><![CDATA[Testing cookies consent compliance proved more difficult than I expected. Here are some tips and tricks I learned while conducting a cookie compliance audit.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img width="1600" height="900" src="https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-2.png" alt="" class="wp-image-8511" srcset="https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-2.png 1600w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-2-300x169.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-2-1024x576.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-2-768x432.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-2-1536x864.png 1536w" sizes="(max-width: 1600px) 100vw, 1600px" /></figure>



<p>In <a href="https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-1-overview/">part one</a> of this series, I shared some high-level thoughts on why organizations are increasingly focused on cookie consent and some things I&#8217;ve learned about how to pick a good solution and roll it out in your organization.</p>



<p>In this article, I want to focus on the more technical aspects of identifying what source is setting a cookie so that you can ensure that your cookie consent solution is handling it properly.</p>



<h2 class="wp-block-heading">Turn off content blockers</h2>



<p>In order to test what cookies <em>could</em> be set, you have to turn off any features that may block cookies. For me, that meant turning down browser privacy setting and turning off extensions like Privacy Badger and uBlock Origin. My home network runs on Eero Plus which also features ad blocking. Everything had to be turned off.</p>



<h2 class="wp-block-heading">Don&#8217;t use default Incognito mode</h2>



<p>Chrome in Incognito mode is my default testing environment. Incognito mode provides a clean slate when I&#8217;m troubleshooting performance issues.</p>



<p>However, I wasn&#8217;t seeing some of the cookies I expected in my tests. Turns out that when Chrome is in Incognito mode, it blocks third-party cookies by default. You can bypass this behavior by clicking on the eye icon in the toolbar.</p>



<p>I used Incognito almost exclusively for my testing which means I&#8217;ve have been doing this wrong for years. </p>



<h2 class="wp-block-heading">Lazy-loading and dynamic cookies</h2>



<p>As I ran my tests, I started to see cookies that only showed up occasionally. I finally figured out that these cookies were set by scripts that were lower on the page and were only loaded when someone scrolled down.</p>



<p>In addition, ad networks can include different scripts which in turn set different cookies based on a user&#8217;s geography, etc. These dynamic insertions are hard to predict. Thankfully, these changing cookies seem primarily limited to ad networks so if you categorize the parent script correctly, then any additional cookies added later will also be categorized correctly.</p>



<h2 class="wp-block-heading">Finding the cookie culprit</h2>



<p>Figuring out what asset set a cookie can be challenging. When you look at the list of cookies in Dev Tools, you can get some hints about what might be setting the cookie from the cookie&#8217;s name and domain. If you&#8217;re lucky, there is only one asset coming from the domain, and you&#8217;ve found your culprit. Most of the time, you won&#8217;t be that lucky.</p>



<p>Unfortunately, the cookie panel doesn&#8217;t contain the equivalent of the <a href="https://www.debugbear.com/docs/request-initiator-chain" data-type="link" data-id="https://www.debugbear.com/docs/request-initiator-chain">initiator column</a> in Chrome&#8217;s network panel. When I&#8217;m conducting performance audits, I rely on the initiator section to help me track down the chain of requests that led to an asset getting downloaded. I&#8217;d love to have something similar for cookies.</p>



<p>Instead, you either need to make some intelligent guesses or create some tooling. Absent tooling, my investigation steps look something like this.</p>



<p>First, I look at the domain name and tracker name to try to determine what service I think might be setting a cookie. For example, a cookie with the domain set to <code>.linkedin.com</code> with the name <code>__cf_bm</code> likely was set by a LinkedIn script and the <code>cf</code> name suggests that the cookie is related to Cloudflare.</p>



<figure class="wp-block-image size-full"><img width="2154" height="1140" src="https://cloudfour.com/wp-content/uploads/2026/03/linkedin-cloudflare.png" alt="Screenshot of the cookies tab in Chrome Dev Tools. A cookie named __cf_bm with the domain .linkedin.com is highlighted." class="wp-image-8502" srcset="https://cloudfour.com/wp-content/uploads/2026/03/linkedin-cloudflare.png 2154w, https://cloudfour.com/wp-content/uploads/2026/03/linkedin-cloudflare-300x159.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/linkedin-cloudflare-1024x542.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/linkedin-cloudflare-768x406.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/linkedin-cloudflare-1536x813.png 1536w, https://cloudfour.com/wp-content/uploads/2026/03/linkedin-cloudflare-2048x1084.png 2048w" sizes="(max-width: 2154px) 100vw, 2154px" /></figure>



<p>I&#8217;ll then look up the cookie using a service like <a href="https://cookiesearch.org/">Cookiesearch.org</a>. In this example, the search will tell me that <a href="https://cookiesearch.org/cookies/?search-term=__cf_bm&amp;filter-type=cookie-name&amp;sort=asc&amp;cookie-id=__cf_bm"><code>__cf_bm</code> is set by Cloudflare</a> and &#8220;is used to support Cloudflare Bot Management.&#8221;</p>



<p>Once I have a domain for the cookie, I turn to the network panel to see if I can find the culprit. I&#8217;ll filter the network panel to only show assets coming from suspect domain.</p>



<figure class="wp-block-image size-full"><img width="2542" height="1192" src="https://cloudfour.com/wp-content/uploads/2026/03/filtering-network-panel.png" alt="Network panel in Dev Tools filtered to only show assets coming from Linkedin." class="wp-image-8503" srcset="https://cloudfour.com/wp-content/uploads/2026/03/filtering-network-panel.png 2542w, https://cloudfour.com/wp-content/uploads/2026/03/filtering-network-panel-300x141.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/filtering-network-panel-1024x480.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/filtering-network-panel-768x360.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/filtering-network-panel-1536x720.png 1536w, https://cloudfour.com/wp-content/uploads/2026/03/filtering-network-panel-2048x960.png 2048w" sizes="(max-width: 2542px) 100vw, 2542px" /></figure>



<p>Cookies can be set by HTTP Headers or JavaScript. HTTP Headers are easier to look for, so I always start there. In the network panel, I look at the response headers for each asset that comes from the suspect domain. The response headers are the headers sent by back the server when the browser requested the asset. The server can ask the browser to create cookies using <code>Set-Cookie</code> headers. There can be more than one <code>Set-Cookie</code> header for a given asset. </p>



<figure class="wp-block-image size-full"><img width="2538" height="1182" src="https://cloudfour.com/wp-content/uploads/2026/03/response-header-setting-cookie.png" alt="" class="wp-image-8504" srcset="https://cloudfour.com/wp-content/uploads/2026/03/response-header-setting-cookie.png 2538w, https://cloudfour.com/wp-content/uploads/2026/03/response-header-setting-cookie-300x140.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/response-header-setting-cookie-1024x477.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/response-header-setting-cookie-768x358.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/response-header-setting-cookie-1536x715.png 1536w, https://cloudfour.com/wp-content/uploads/2026/03/response-header-setting-cookie-2048x954.png 2048w" sizes="(max-width: 2538px) 100vw, 2538px" /></figure>



<p>If the cookie isn&#8217;t set using HTTP Headers, it can be more difficult to isolate which bit of JavaScript is setting the cookie. I often use <a href="https://developer.chrome.com/docs/devtools/request-conditions">request blocking</a> in the network panel as a blunt tool to isolate which script sets the cookies.</p>



<figure class="wp-block-image size-full"><img width="2546" height="1536" src="https://cloudfour.com/wp-content/uploads/2026/03/blocking-a-request.png" alt="" class="wp-image-8505" srcset="https://cloudfour.com/wp-content/uploads/2026/03/blocking-a-request.png 2546w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-a-request-300x181.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-a-request-1024x618.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-a-request-768x463.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-a-request-1536x927.png 1536w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-a-request-2048x1236.png 2048w" sizes="(max-width: 2546px) 100vw, 2546px" /><figcaption class="wp-element-caption">Right-clicking on an asset in the network panel will provide an option to Block Requests. You can block them by URL or by domain.</figcaption></figure>



<figure class="wp-block-image size-full"><img width="2560" height="1517" src="https://cloudfour.com/wp-content/uploads/2026/03/blocking-and-throttling-panel-scaled.png" alt="" class="wp-image-8507" srcset="https://cloudfour.com/wp-content/uploads/2026/03/blocking-and-throttling-panel-scaled.png 2560w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-and-throttling-panel-300x178.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-and-throttling-panel-1024x607.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-and-throttling-panel-768x455.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-and-throttling-panel-1536x910.png 1536w, https://cloudfour.com/wp-content/uploads/2026/03/blocking-and-throttling-panel-2048x1214.png 2048w" sizes="(max-width: 2560px) 100vw, 2560px" /><figcaption class="wp-element-caption">After you choose to block a request, the Request Conditions drawer will open. This is where you can turn on and off request blocking and throttling. You can also edit the regular expressions and fine-tune what assets are blocked.</figcaption></figure>



<p>First, I&#8217;ll block the entire request domain, clear all cookies, and then check to see if the cookie is still getting set. If it is, I&#8217;m looking at the wrong source. If the cookie is no longer being set, I now know that one of the assets I blocked is responsible.</p>



<p>Often I&#8217;m able to make an educated guess about which asset is likely to set the cookie based on the description of the cookie and the asset names. If I have a hunch, I&#8217;ll try blocking that asset alone and see if the cookie is still set.</p>



<p>If I don&#8217;t have a guess or I guessed wrong, I&#8217;ll narrow it down by blocking half the requests from the suspect domain to see if that blocks the cookie. If it does, I know where to continue looking. If not, the cookie must be set in the other half. Repeat this a few more times and you can quickly winnow down even a long list of assets.</p>



<h2 class="wp-block-heading">Cookies blocked by the browser</h2>



<p>Cookies that were blocked by the browser may still show up in cookie list to help with troubleshooting. Their row will be distinguished in a different color and if you hover over the associated request, you will see information about why the cookie was rejected.</p>



<figure class="wp-block-image size-full"><img width="2424" height="548" src="https://cloudfour.com/wp-content/uploads/2026/03/twitter-blocked-cookie.png" alt="" class="wp-image-8508" srcset="https://cloudfour.com/wp-content/uploads/2026/03/twitter-blocked-cookie.png 2424w, https://cloudfour.com/wp-content/uploads/2026/03/twitter-blocked-cookie-300x68.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/twitter-blocked-cookie-1024x231.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/twitter-blocked-cookie-768x174.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/twitter-blocked-cookie-1536x347.png 1536w, https://cloudfour.com/wp-content/uploads/2026/03/twitter-blocked-cookie-2048x463.png 2048w" sizes="(max-width: 2424px) 100vw, 2424px" /><figcaption class="wp-element-caption">In this screenshot, there are three cookies highlighted with a slightly different shade of brown. If you hover over the information icons in each row, you&#8217;ll see why the cookie was blocked. In this case, the twitter.com cookie was blocked because it didn&#8217;t specify a SameSite attribute which is required for a cross-origin cookie.</figcaption></figure>



<h2 class="wp-block-heading">Testing using a headless browser</h2>



<p>Manual testing can only get you so far. I had to audit hundreds of cookies for a client, so I looked for ways to automate the process. I couldn&#8217;t find anything that did exactly what I needed so with Claude Code&#8217;s help, I wrote a command line tool that used <a href="https://pptr.dev/">Puppeteer</a> to see which cookies were set before and after consent was granted.</p>



<p>Puppeteer helped me find cookies that my manual testing had missed. Every time Puppeteer launches, it has a clean slate. Therefore, any cookies that my script finds must have been set by the test page. This helped capture third-party cookies that were only showing up on the first page load. </p>



<p>I also added logic to intercept cookies being set to create my own version of the the initiator chain. Eventually, I expanded the tests to look for local storage, session storage, and IndexDB. Puppeteer also scrolls the page to make sure it captures any lazy loading cookies.</p>



<p>If you need to do any significant amount of testing, I recommend using Puppeteer, or its alternative <a href="https://playwright.dev/">Playwright</a>, so you have a clean testing environment and can automate the process.</p>



<h2 class="wp-block-heading">Cookie consent can be fun?</h2>



<p>When our clients first asked for help with their cookie consent management, I wasn&#8217;t looking forward to it. I like designing and building solutions for users not dealing with legal requirements. Plus, cookie consent banners are annoying.</p>



<p>But by the end of these projects, I found myself enjoying the work. The cookie consent tools do a good job of recognizing most cookies, but there are always a few mysteries in the box. I love a good mystery. And sometimes you find truly surprising things like a site manifest file setting multiple cookies.</p>



<p>Plus, there is satisfaction in knowing that people will have their privacy preferences honored. Not to mention the fact that we&#8217;re able to significantly reduce the legal risk for our customers.</p>



<p>Cookie consent management can seem daunting at first, but it is important for your organization and its users. And maybe I&#8217;m just a sicko, but I found it to be a lot of fun.</p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-2-technical-tips/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8509</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-2.png" width="550" height="309" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-2.png" length="0" type="image/png" />	</item>
		<item>
		<title>Cookie Consent Management in 2026, Part 1: Overview</title>
		<link>https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-1-overview/</link>
					<comments>https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-1-overview/#respond</comments>
		
		<dc:creator><![CDATA[Jason Grigsby]]></dc:creator>
		<pubDate>Wed, 18 Mar 2026 18:31:50 +0000</pubDate>
				<category><![CDATA[Essentials]]></category>
		<category><![CDATA[Privacy]]></category>
		<category><![CDATA[featured/articles]]></category>
		<category><![CDATA[featured/home]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8494</guid>

					<description><![CDATA[The threat of lawsuits has companies scrambling to get their cookie compliance house in order. Here are some of the things we've learned as we've helped our clients.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img width="1600" height="900" src="https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-1.png" alt="" class="wp-image-8510" srcset="https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-1.png 1600w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-1-300x169.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-1-1024x576.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-1-768x432.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-1-1536x864.png 1536w" sizes="(max-width: 1600px) 100vw, 1600px" /></figure>



<p>I&#8217;ve noticed a trend. Over the last few months, multiple customers have asked us to help with cookie consent compliance. Either it is a mighty coincidence or something has caused companies to start taking privacy compliance more seriously.</p>



<p>I think the renewed interest is because ambitious lawyers have started sending <a href="https://www.pierceatwood.com/alerts/pre-suit-privacy-and-consumer-law-demand-letters-surge-2025-how-businesses-can-stay-ahead#:~:text=Plaintiffs'%20firms%20are%20testing%20decades,early%20pre%2Dlitigation%20demand%20stages." data-type="link" data-id="https://www.pierceatwood.com/alerts/pre-suit-privacy-and-consumer-law-demand-letters-surge-2025-how-businesses-can-stay-ahead#:~:text=Plaintiffs'%20firms%20are%20testing%20decades,early%20pre%2Dlitigation%20demand%20stages.">threatening letters</a> to companies that aren&#8217;t in compliance with the California Consumer Privacy Act (CCPA) and the EU&#8217;s General Data Protection Regulation (GDPR) provisions. I know of at least one company with over $100k in related legal fees.</p>



<p>Last month, California won a <a href="https://iapp.org/news/a/california-s-attorney-general-issues-largest-ccpa-fine-to-date">$2.75M settlement with Disney </a>over CCPA violations. CCPA fines can add up quickly. They start at $2,663 per incident. The fines increases to $7,988 per incident for willful violations or violations involving people under 16.</p>



<p>It&#8217;s not limited to CCPA and GPDR. Enterprising lawyers have dusted off the 1967 California Invasion of Privacy Act (CIPA) and applied it to web technology. The law firm Varnum <a href="https://www.varnumlaw.com/insights/the-rise-of-cipa-website-tracking-claims/">explains</a>:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Plaintiffs’ attorneys are using CIPA to challenge common website technologies, including cookies, analytics tools, session replay software, and chat features. Many companies are caught off guard when they receive a demand letter alleging unlawful website tracking, followed by the threat of litigation.</p>



<p>Thousands of CIPA website tracking claims have been asserted, and filings continue to rise.</p>
</blockquote>



<p>So it&#8217;s not surprising that companies are trying to get their cookie house in order. I may be a glutton for punishment, but I&#8217;ve enjoyed working on these cookie consent projects, and thought I&#8217;d share some of the things I&#8217;ve learned. In part one, I&#8217;ll share some high-level thoughts. In <a href="https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-2-technical-tips/" data-type="link" data-id="https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-2-technical-tips/">part 2</a>, I&#8217;ll dig into some technical details.</p>



<h2 class="wp-block-heading">Organizational resistance</h2>



<p>When an organization implements cookie consent management for the first time, the impact on their analytics and marketing initiatives can be dramatic. If people can opt out of being tracked, a significant percentage will choose to do so. If your marketing relies on tracking, it will suffer.</p>



<p>I know of an organization that backtracked on cookie compliance because of the impact on marketing. Doing so creates legal exposure, but it&#8217;s understandable how a company that sees their sales drop might panic.</p>



<p>So my first piece of advice is to talk to marketing ahead of time to understand what tools are being used. Determine which are most likely to be impacted by cookie banners, and see what you can do to mitigate them. Sign up now for a GPDR-compliant, cookie-less analytics service like <a href="https://plausible.io/" data-type="link" data-id="https://plausible.io/">Plausible</a> or <a href="https://umami.is/" data-type="link" data-id="https://umami.is/">Umami</a> so you have a baseline of analytics information. You can use these services track trends before and after you implement a consent banner.</p>



<p>Unfortunately, in a lot situations, there isn&#8217;t much you can do to alleviate the data loss. If someone doesn&#8217;t want to be tracked and your marketing tools depend on tracking data, then the tools are going to be less effective. But helping your marketing colleagues anticipate where cookie consent will impact them will not only help mitigate data loss, but it will also prepare the team for their new reality.</p>



<h2 class="wp-block-heading">Hire a good lawyer</h2>



<p>I&#8217;m not a lawyer. If you&#8217;re reading this, you&#8217;re probably not either. You need knowledgable legal counsel to help you decide how cookies should be categorized. Only a lawyer can help an organization make sure they are in compliance and understand the risks of various choices.</p>



<p>Plus, if you&#8217;re the person leading the privacy charge, then the people are going to resist you. Instead, if a lawyer tells your organization what they need to do, then you don&#8217;t have to argue with co-workers about whether their favorite service&#8217;s cookies should be defined as essential or not. You get to be the hero helping the organization while the lawyer plays the bad cop.</p>



<h2 class="wp-block-heading">Find a good cookie consent solution</h2>



<p>I find cookie consent banners annoying. As a user, I didn&#8217;t care what solution a website used so long as I could dismiss it quickly.</p>



<p>But after working with a few different cookie consent solutions for our clients, I now have a list of features I consider critical:</p>



<ul class="wp-block-list">
<li><strong>GPDR compliant</strong>: You may only care about CCPA right now, but CCPA is evolving towards GPDR. In fact, even though one of our clients is based in California and doesn&#8217;t sell in Europe, their lawyers advised them to use a GPDR-style cookie consent banner where you can select specific categories of cookies instead of a CCPA-compliant one where you either accept or reject cookies.</li>



<li><strong>Regular scanning of your site: </strong>What cookies are being used on your site may change over time without you knowing about it either because a new third-party service is added to the site or an existing one adds a new cookie. You need regular scans to tell you if a cookie has been discovered so you can categorize it.</li>



<li><strong>Identifies local storage, session storage, and IndexDB in addition to cookies</strong>: Even though everyone talks about cookies, the privacy laws don&#8217;t care what technical mechanism is used to track people. You need a tool that looks at all of the ways people can be tracked.</li>



<li><strong>Intuitive web-based reports</strong>: We&#8217;ve worked with one cookie consent manager where account managers send periodic spreadsheets that appear to be manually generated. By contrast, my favorite provider has an easy-to-use web report that shows what cookies their scans have discovered and how to take action on them.</li>



<li><strong>A solution that is lightweight and fast</strong>:&nbsp;Cookie consent banners have to load early on the page and block other scripts. Therefore, any performance issues they have are magnified.</li>
</ul>



<p>On that last point, I asked the web performance Slack community if anyone had recommendations for a performant cookie solution. The kind folks at <a href="https://www.rumvision.com/">RUMVision</a> shared data from across their customer base:</p>



<figure class="wp-block-image size-full"><a href="https://cloudfour.com/wp-content/uploads/2026/03/cookie-consent-js-execution.png"><img width="2241" height="751" src="https://cloudfour.com/wp-content/uploads/2026/03/cookie-consent-js-execution.png" alt="Low impact cookie consent managers include: CookieLaw.org, CookieYes.com, OneTrust.com, Cookiecode.nl, Usercentrics.eu, and PrivacyManager.io." class="wp-image-8495" srcset="https://cloudfour.com/wp-content/uploads/2026/03/cookie-consent-js-execution.png 2241w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-consent-js-execution-300x101.png 300w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-consent-js-execution-1024x343.png 1024w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-consent-js-execution-768x257.png 768w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-consent-js-execution-1536x515.png 1536w, https://cloudfour.com/wp-content/uploads/2026/03/cookie-consent-js-execution-2048x686.png 2048w" sizes="(max-width: 2241px) 100vw, 2241px" /></a></figure>



<p>Because I have a performance hammer and everything is a nail, I started my explorations with <a href="https://www.cookieyes.com/partner-offer/?ref=yzqynjn">CookieYes</a> (That&#8217;s an affiliate link. If you sign up, we get a <em>tiny</em> kickback.) It is almost twice as fast as the nearest competitor in the RumVision data.</p>



<p>I&#8217;ve been quite happy with CookieYes. It is reasonably priced. The administrative dashboard is easy to work with. The scans surface cookies we need to address. Most importantly, their support has been fast and knowledgeable.</p>



<h2 class="wp-block-heading">Monitor your compliance</h2>



<p>Complying with privacy laws requires some form of ongoing vigilance. Unless you are not using any third-party services, the cookies being used on your site may change without your knowledge. Therefore, you need regular scans and people who are responsible for addressing any new issues that arise.</p>



<p>In larger organizations, you have to keep an eye out for other teams creating new websites. These websites need to be integrated with your main cookie consent solution. If someone opts out on one of your websites, their decision should carry over to others. This may require all company websites to use subdomains so cookie consent decisions can be more easily shared between them.</p>



<p>The privacy laws themselves change. As of January this year, CCPA not only requires websites to honor a user&#8217;s <a href="https://globalprivacycontrol.org/">Global Privacy Control (GPC) setting</a>, but also <a href="https://www.clym.io/blog/ccpa-selling-and-sharing-what-counts-as-a-sale-or-share">explicitly notify them</a> that it has been honored.</p>



<p>The good news is that while you do need to monitor cookies and privacy laws to make sure you remain in compliance, the ongoing work is minimal once you tackle the initial audit, categorization, and implementation of a cookie consent banner.</p>



<p>In <a href="https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-2-technical-tips/">part 2</a> of this series, I&#8217;ll share some technical tips and tricks I learned for identifying the source of cookies.</p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/cookie-consent-management-in-2026-part-1-overview/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8494</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-1.png" width="550" height="309" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/03/cookie-2026-feature-part-1.png" length="0" type="image/png" />	</item>
		<item>
		<title>Little Dummies: Simple FPO Content Helpers</title>
		<link>https://cloudfour.com/thinks/little-dummies-simple-fpo-content-helpers/</link>
					<comments>https://cloudfour.com/thinks/little-dummies-simple-fpo-content-helpers/#respond</comments>
		
		<dc:creator><![CDATA[Tyler Sticka]]></dc:creator>
		<pubDate>Thu, 12 Mar 2026 21:26:26 +0000</pubDate>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Process]]></category>
		<category><![CDATA[Responsive Web Design]]></category>
		<category><![CDATA[SVG]]></category>
		<category><![CDATA[Tools]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8497</guid>

					<description><![CDATA[Video, links and code samples from my rapid prototyping talk for the final Eleventy Meetup.]]></description>
										<content:encoded><![CDATA[
<p>I was delighted to present this talk at the final (for now) episode of <a href="https://11tymeetup.dev">The Eleventy Meetup</a>:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><s>Eleventy</s> <a href="https://www.11ty.dev/blog/build-awesome/">Build Awesome</a> is great for rapid prototyping! Tyler shows off a few of his favorite shortcodes, filters and other techniques to quickly populate interactive mockups and wireframes with “dummy” or FPO (for placement only) content.</p>
</blockquote>



<p>You can watch the presentation here:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="Little Dummies: Simple FPO Content Helpers with Tyler Sticka | 11ty Meetup" width="500" height="281" src="https://www.youtube.com/embed/NHgiKb8XfU0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div></figure>



<h2 class="wp-block-heading">Example Helpers</h2>



<p>These are the main code samples from my slides, consolidated below for easy reference.</p>



<p>Each helper is written in ESM syntax (but should work in CommonJS with <a href="https://www.11ty.dev/docs/cjs-esm/#common-js-configuration">a few small changes</a>), and each assumes it lives in its own file (imported by <a href="https://www.11ty.dev/docs/config/">the config</a>).</p>



<h3 class="wp-block-heading">Text, Numbers, etc.</h3>



<p>With the <a href="https://chancejs.com/">Chance</a> dependency:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">import</span> Chance <span class="hljs-keyword">from</span> <span class="hljs-string">"chance"</span>;
<span class="hljs-keyword">let</span> chance;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">method, ...args</span>) </span>{
  <span class="hljs-comment">// Support JSON string for first argument</span>
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> args&#91;<span class="hljs-number">0</span>] === <span class="hljs-string">"string"</span>) {
    args&#91;<span class="hljs-number">0</span>] = <span class="hljs-built_in">JSON</span>.parse(args&#91;<span class="hljs-number">0</span>]);
  }

  <span class="hljs-comment">// Instantiate Chance the first time</span>
  <span class="hljs-keyword">if</span> (!chance) {
    chance = <span class="hljs-keyword">new</span> Chance();
  }

  <span class="hljs-comment">// If the method exists, return its output</span>
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> chance&#91;method] === <span class="hljs-string">"function"</span>) {
    <span class="hljs-keyword">return</span> chance&#91;method](...args);
  }

  <span class="hljs-comment">// Otherwise, log an error but proceed</span>
  <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`&#91;chance] No method named <span class="hljs-subst">${methodName}</span>`</span>);
  <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>;
}</code></span></pre>


<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Eleventy Config Example</summary><pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">import</span> chanceHelper <span class="hljs-keyword">from</span> <span class="hljs-string">"./helpers/chance.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">eleventyConfig</span>) </span>{
  eleventyConfig.addShortcode(<span class="hljs-string">"chance"</span>, chanceHelper);
  eleventyConfig.addFilter(<span class="hljs-string">"chance"</span>, chanceHelper);
}</code></span></pre></details>



<h3 class="wp-block-heading">Images</h3>



<p>With our <a href="https://cloudfour.com/thinks/simple-svg-placeholder/">Simple SVG Placeholder</a> dependency:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">import</span> simpleSvgPlaceholder <span class="hljs-keyword">from</span> <span class="hljs-string">"@cloudfour/simple-svg-placeholder"</span>;

<span class="hljs-comment">/**
 * Modify these to suit the project!
 * @see https://github.com/cloudfour/simple-svg-placeholder#option-reference
 */</span>
<span class="hljs-keyword">const</span> defaults = {
  <span class="hljs-attr">bgColor</span>: <span class="hljs-string">"rgb(0 0 0 / 0.8)"</span>,
  <span class="hljs-attr">textColor</span>: <span class="hljs-string">"white"</span>,
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">width, height, options = {}</span>) </span>{
  <span class="hljs-comment">// Support JSON string for argument</span>
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> options === <span class="hljs-string">"string"</span>) {
    options = <span class="hljs-built_in">JSON</span>.parse(options);
  }

  <span class="hljs-keyword">return</span> simpleSvgPlaceholder({...defaults, width, height, ...options});
}</code></span></pre>


<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Eleventy Config Example</summary><pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">import</span> fpoImageHelper <span class="hljs-keyword">from</span> <span class="hljs-string">"./helpers/fpo-image.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">eleventyConfig</span>) </span>{
  eleventyConfig.addShortcode(<span class="hljs-string">"fpoImage"</span>, fpoImageHelper);
}</code></span></pre></details>



<h3 class="wp-block-heading">Icons</h3>



<p>This example uses <a href="https://iconify.design/docs/api/">the Iconify API</a> via <a href="https://www.11ty.dev/docs/plugins/fetch/">Eleventy Fetch</a>.</p>



<p>I&#8217;ve made a small enhancement since the presentation, adding <a href="https://github.com/fb55/entities">the entities package</a> to escape attribute values on the inline SVG based on a recommendation from Zach Leatherman:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">import</span> EleventyFetch <span class="hljs-keyword">from</span> <span class="hljs-string">"@11ty/eleventy-fetch"</span>;
<span class="hljs-keyword">import</span> { escapeAttribute } <span class="hljs-keyword">from</span> <span class="hljs-string">"entities/escape"</span>;

<span class="hljs-keyword">const</span> apiUrl = <span class="hljs-string">"https://api.iconify.design"</span>;

<span class="hljs-keyword">const</span> fetchOptions = {
  <span class="hljs-attr">duration</span>: <span class="hljs-string">"1y"</span>,
  <span class="hljs-attr">type</span>: <span class="hljs-string">"json"</span>,
};

<span class="hljs-keyword">const</span> defaultAttr = {
  <span class="hljs-attr">xmlns</span>: <span class="hljs-string">"http://www.w3.org/2000/svg"</span>,
  <span class="hljs-attr">class</span>: <span class="hljs-string">"icon"</span>,
};

<span class="hljs-comment">// Get a specific set:name icon string</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getSpecificIcon</span>(<span class="hljs-params">icon</span>) </span>{
  <span class="hljs-comment">// If already specific, do nothing</span>
  <span class="hljs-keyword">if</span> (icon.includes(<span class="hljs-string">":"</span>)) {
    <span class="hljs-keyword">return</span> icon;
  }

  <span class="hljs-keyword">const</span> searchUrl = <span class="hljs-string">`<span class="hljs-subst">${apiUrl}</span>/search?query=<span class="hljs-subst">${icon}</span>&amp;limit=1`</span>;
  <span class="hljs-keyword">const</span> searchData = <span class="hljs-keyword">await</span> EleventyFetch(searchUrl, fetchOptions);
  <span class="hljs-keyword">const</span> results = searchData.icons || &#91;];

  <span class="hljs-keyword">if</span> (results.length === <span class="hljs-number">0</span>) {
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`No icon found for <span class="hljs-subst">${icon}</span>`</span>);
  }

  <span class="hljs-keyword">return</span> results&#91;<span class="hljs-number">0</span>];
}

<span class="hljs-comment">// { class: "icon", width: 120 }</span>
<span class="hljs-comment">// =&gt; 'class="icon" width="120"'</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">objectToAttributeString</span>(<span class="hljs-params">obj</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Object</span>.entries(obj)
    .map(<span class="hljs-function">(<span class="hljs-params">&#91;key, value]</span>) =&gt;</span> {
      value = escapeAttribute(<span class="hljs-string">`<span class="hljs-subst">${value}</span>`</span>);
      <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${key}</span>="<span class="hljs-subst">${value}</span>"`</span>;
    })
    .join(<span class="hljs-string">" "</span>);
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">icon, attr = {}</span>) </span>{
  <span class="hljs-comment">// Support JSON strings for attributes</span>
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> attr === <span class="hljs-string">"string"</span>) {
    attr = <span class="hljs-built_in">JSON</span>.parse(attr);
  }

  <span class="hljs-keyword">try</span> {
    icon = <span class="hljs-keyword">await</span> getSpecificIcon(icon);
    <span class="hljs-keyword">const</span> &#91;setName, iconName] = icon.split(<span class="hljs-string">":"</span>);
    <span class="hljs-keyword">const</span> iconDataUrl = <span class="hljs-string">`<span class="hljs-subst">${apiUrl}</span>/<span class="hljs-subst">${setName}</span>.json?icons=<span class="hljs-subst">${iconName}</span>`</span>;
    <span class="hljs-keyword">const</span> iconData = <span class="hljs-keyword">await</span> EleventyFetch(iconDataUrl, fetchOptions);

    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> iconData !== <span class="hljs-string">"object"</span>) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Request for <span class="hljs-subst">${icon}</span> returned <span class="hljs-subst">${iconData}</span>`</span>);
    }

    <span class="hljs-keyword">const</span> { width, height } = iconData;
    <span class="hljs-keyword">const</span> { body } = iconData.icons&#91;iconName];
    <span class="hljs-keyword">const</span> attrString = objectToAttributeString({
      ...defaultAttr,
      <span class="hljs-string">"data-icon"</span>: icon,
      <span class="hljs-attr">viewBox</span>: <span class="hljs-string">`0 0 <span class="hljs-subst">${width}</span> <span class="hljs-subst">${height}</span>`</span>,
      width,
      height,
      ...attr
    });

    <span class="hljs-keyword">return</span> <span class="hljs-string">`&lt;svg <span class="hljs-subst">${attrString}</span>&gt;<span class="hljs-subst">${body}</span>&lt;/svg&gt;`</span>;
  } <span class="hljs-keyword">catch</span>(err) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`&#91;iconify] <span class="hljs-subst">${err.message}</span>`</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>;
  }
}</code></span></pre>


<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Eleventy Config Example</summary><pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">import</span> iconifyHelper <span class="hljs-keyword">from</span> <span class="hljs-string">"./helpers/iconify.js"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">eleventyConfig</span>) </span>{
  eleventyConfig.addShortcode(<span class="hljs-string">"iconify"</span>, iconifyHelper);
}</code></span></pre></details>



<h2 class="wp-block-heading">Resources</h2>



<p>More references from the talk (other than dependencies in the previous section):</p>



<ul class="wp-block-list">
<li>For more about Cloud Four&#8217;s process, check out <a href="https://cloudfour.com/thinks/responsive-design-process-that-works/">Responsive Design Process That Works</a> and <a href="https://cloudfour.com/made/imagequix/">one of our case studies</a></li>



<li><a href="https://cloudfour.com/thinks/why-i-like-designing-in-the-browser/">Why I Like Designing in the Browser</a> and <a href="https://cloudfour.com/thinks/designing-in-the-browser-five-tips-for-beginners/">five tips for beginners</a></li>



<li>Build Awesome provides helpful docs for <a href="https://www.11ty.dev/docs/shortcodes/">Shortcodes</a> and <a href="https://www.11ty.dev/docs/filters/">Filters</a></li>



<li>If you already have an icon library, check out <a href="https://github.com/uncenter/eleventy-plugin-icons">uncenter&#8217;s awesome plugin</a></li>



<li><a href="https://danross.co/flow/">Flow</a> and <a href="https://github.com/christiannaths/redacted-font">Redacted</a> are fonts intended for stubbing out text sections in wireframes</li>



<li>Performance chart from <a href="https://almanac.httparchive.org/en/2025/page-weight">the Page Weight section of the 2025 Web Almanac</a></li>



<li>Accessibility chart from <a href="https://webaim.org/projects/million/#wcag">The WebAIM Million&#8217;s WCAG Conformance section</a></li>



<li><a href="https://xkcd.com/3175/">XKCD&#8217;s Website Task Flowchart cartoon</a></li>
</ul>



<h2 class="wp-block-heading">Some Questions Answered</h2>



<p>Two questions stood out to me during a live Q&amp;A following my presentation:</p>



<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Do you only prototype in Eleventy / Build Awesome?</summary>
<p>No! Sometimes the teams we work with already have an environment with <a href="https://cloudfour.com/thinks/encouraging-play-in-design-systems/">a suitable playground</a>, or a different stack they&#8217;re more familiar with. But Build Awesome is a great fallback due to its stability, performance, flexibility and <a href="https://cloudfour.com/thinks/tiny-web-stacks/">small footprint</a>.</p>
</details>



<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Do you share these sorts of helpers between projects? </summary>
<p>We start from a private, opinionated <a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository">template repository</a>, which we tailor to the project&#8217;s needs. After a major milestone, we&#8217;ll see if anything we diverged on deserves to be added back to the template repo to benefit future projects. This allows us to easily adapt the helpers to the needs of the project without sweating breaking changes.</p>
</details>



<h2 class="wp-block-heading">Acknowledgements</h2>



<p>Big thanks to <a href="https://sia.codes">Sia Karamalegos</a> for having me, <a href="https://www.zachleat.com">Zach Leatherman</a> for creating Build Awesome (<a href="https://www.kickstarter.com/projects/fontawesome/build-awesome-pro">new Kickstarter launching soon</a>) and encouraging my unique possum interpretations, and especially everyone who attended the meetup!</p>



<p>If you want to see Cloud Four&#8217;s process in action, <a href="https://cloudfour.com/and-you/">get in touch</a>! We&#8217;re always looking for our next web app design challenge.</p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/little-dummies-simple-fpo-content-helpers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8497</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/03/11ty-dummies-post-feature-r1.jpg" width="550" height="309" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/03/11ty-dummies-post-feature-r1.jpg" length="0" type="image/jpg" />	</item>
		<item>
		<title>How We Do Code Reviews at Cloud Four</title>
		<link>https://cloudfour.com/thinks/how-we-do-code-reviews-at-cloud-four/</link>
					<comments>https://cloudfour.com/thinks/how-we-do-code-reviews-at-cloud-four/#respond</comments>
		
		<dc:creator><![CDATA[Scott Vandehey]]></dc:creator>
		<pubDate>Wed, 04 Mar 2026 16:30:00 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[bestpractices]]></category>
		<category><![CDATA[codereview]]></category>
		<category><![CDATA[pullrequests]]></category>
		<category><![CDATA[review]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8489</guid>

					<description><![CDATA[If your team members dread the notification that they’ve been added as a reviewer on a pull request, I think the following guidelines can help.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img width="1024" height="576" src="https://cloudfour.com/wp-content/uploads/2026/03/feature-code-review-r4-1024x576.jpg" alt="Cartoon illustration showing one person struggling under the weight of an enormous cardboard box labeled “PR”, while the person they're trying to hand it to recoils in alarm." class="wp-image-8491" srcset="https://cloudfour.com/wp-content/uploads/2026/03/feature-code-review-r4-1024x576.jpg 1024w, https://cloudfour.com/wp-content/uploads/2026/03/feature-code-review-r4-300x169.jpg 300w, https://cloudfour.com/wp-content/uploads/2026/03/feature-code-review-r4-768x432.jpg 768w, https://cloudfour.com/wp-content/uploads/2026/03/feature-code-review-r4-1536x864.jpg 1536w, https://cloudfour.com/wp-content/uploads/2026/03/feature-code-review-r4-2048x1152.jpg 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Does this sound familiar to you?</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Chat, is it good when your AI-obsessed colleague drops a +16,105 -193 pull request with 102 commits all titled “wip: implement next task” and asks that it be immediately approved for next release?<br>— <a href="https://bsky.app/profile/eva.town/post/3mf2zrihi222y">eva</a></p>
</blockquote>



<p>The issue isn&#8217;t AI specifically, but the speed with which contributors can generate massive amount of code, exposing weaknesses in a team&#8217;s workflow.</p>



<p>Cloud Four is currently a small agency, with only a handful of devs. We often work together with our client’s internal developers, or with contractors. Because of this, we’ve developed a set of best practices that I’m quite proud of. If your team members dread the notification that they’ve been added as a reviewer on a pull request, I think the following guidelines can help.</p>



<h2 class="wp-block-heading">All Code Gets Reviewed</h2>



<p>Our first rule is a strict one. If a code change is going to production, it gets reviewed. We work for clients, so “move fast and break things” isn’t a realistic way to do business. If I get sloppy and push unreviewed code that causes an incident, I’ve put the client in a bad spot, triggered an urgent crisis for my team to deal with, and perhaps jeopardized our client relationship.</p>



<p>In every code repository we work in, <a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule">we recommend enabling protection rules for the production branch</a>. GitHub makes it easy to require a pull request before merging, and to require pull requests be approved by someone other than the author. The only exception we make is to grant certain senior developers permission to bypass these rules for safe changes like minor dependency updates.</p>



<p>I know teams that require two developers to review every pull request. Normally, one dev can be the person who submitted the PR, but in the case of AI-authored pull requests, two human devs still need to review it. That’s a clever way to ensure automated code gets a bit more attention than normal.</p>



<p>The natural consequence of requiring a review for all code is the dev team has to actually review all that code. This can be time-consuming, and if you don’t already have a team culture that values code review, this may be a tough pill to swallow. The rest of our guidelines are aimed at reducing the burden placed on code reviewers.</p>



<h2 class="wp-block-heading">Prefer Many Small PRs Over One Giant PR</h2>



<p>Firstly, we absolutely reserve the right to reject massive pull requests like the one described in the introduction. A common problem we run into is pull requests that make multiple unrelated changes, such as including a refactoring pass alongside new features or bug fixes. When I see this happen, I’ll reach out to the dev in a non-confrontational way and explain that by combining all their changes like this, it makes the reviewer’s task much more difficult.</p>



<p>Here are some things we’ll commonly ask a dev to pull out into a separate pull request:</p>



<ul class="wp-block-list">
<li><strong>Lint rule changes</strong> that result in many files being changed at once. This happens, but there’s no reason to combine it with anything else. It’s easier to review dozens of similar file changes when there’s no unrelated changes lurking in the code. Plus, it simplifies the acceptance criteria for the lint changes if you don’t expect any impact on functionality.</li>



<li><strong>Moving code</strong> from one location to another. If there’s a huge block of red in one file, and a huge block of green in another file, and a comment saying “no changes, just relocated this code for [reasons],” that’s trivial to review. On the other hand, if the code moved and there are <em>also</em> unrelated changes, the code diff doesn’t show those changes. It’s far easier to review if you break it up into one PR to move the code, and another to modify it.</li>



<li><strong>Unrelated bug fixes</strong> or features. I know it’s tempting to fix a bug you noticed while you were in that file, or to update some code to modern standards, but that just adds noise for the reviewer. It’s totally fine to file a second pull request at the same time, making that bug fix.</li>
</ul>



<p>Once your team gets the hang of it, you’ll see fewer monster pull requests, and your team will become more comfortable pushing back on unnecessarily large pull requests in general.</p>



<h2 class="wp-block-heading">Explain Why This Change is Needed</h2>



<p>A pull request should not just explain what changes are being made, it should explain <em>why</em> they’re being made. That context is incredibly valuable to anyone who isn’t intimately familiar with the code you’re changing. Whether that’s your fellow dev who is taking time away from their tasks in a different part of the code base, someone who works on another team entirely, or yourself in the future.</p>



<p>I want to emphasize that last one. I can’t tell you how many times I’ve been trying to figure out why some feature works the way it does, and when I dive into <code>git blame</code> I see my name staring back at me. When I track the change back to a commit I authored with a well-written description, I’m relieved. Conversely, when I find a simple “change the client wanted” comment, I want to pull my hair out.</p>



<p>The same is true of any developer who ends up reviewing your code. Give them the context for why you’re making this change. What problem were you solving? Why was this the best solution? Armed with this information, your reviewer will have an easier time.</p>



<h2 class="wp-block-heading">Provide Thorough Testing Instructions</h2>



<p>The phrase “acceptance criteria” isn’t just for project managers! After a good description of why the change is being made, we like to provide <em>detailed</em> testing instructions. We started this when we were working with some new contractors, who didn’t necessarily have a full picture of how to test the application. It&#8217;s also proven valuable when non-developers step in to help out while we’re facing an impending deadline.</p>



<p>Don’t assume the person who is testing your pull request knows how to work with your app. We often literally provide step-by-step checklists like this:</p>



<ul class="wp-block-list">
<li>Check out this branch in your local environment</li>



<li>Set <code>new_feature_flag</code> in <code>config.js</code> to <code>true</code></li>



<li>Start the app and navigate to <code>/new-feature</code></li>



<li>Apply a filter using the hamburger menu in the top-right</li>



<li>You should see the list of cards has been filtered</li>



<li>Remove the filter</li>



<li>Now you should see all the cards again</li>



<li>Etc…</li>
</ul>



<p>This might feel like overkill, especially if another dev on your team will review it. But remember that other dev may be working on another part of your application, and hasn’t been paying careful attention to the part you’re working on. A checklist like this, that doesn’t assume the reviewer already knows how to test your feature, reduces the burden on any reviewer, and even opens the door to less-technically minded team members helping with testing.</p>



<p>Another benefit of this approach is that writing out testing instructions gives you an opportunity to follow those instructions. I can’t tell you how often, in the course of writing a step-by-step checklist for a pull request, I’ve uncovered an issue. If I can address that before the reviewer starts, I’m saving everyone time.</p>



<p>Bonus: writing testing instructions for a human tends to give you a clear idea for automated tests. After all, if you know how it should work, why not let your CI workflow check it for you?</p>



<h2 class="wp-block-heading">Code Review is a Culture Issue</h2>



<p>What all these suggestions have in common is being aware of the cognitive burden on another developer who may be stepping away from their assigned tasks to think about yours. Context switching is a productivity killer, and anything you can do to make it easier for someone else to review your code helps avoid code review becoming something your team members dread.</p>



<p>Requiring all code be reviewed before going to production shows you value the quality of what you ship. Asking your team to prefer small pull requests over large ones helps reduce the scope of review. Providing context for why a change was made helps the reviewer understand those decisions. And providing clear testing instructions means reviewers don’t get derailed figuring out how to test the changes.</p>



<p>All of this adds up to a culture that expects quality code, values the time it takes to review it, and respects the team’s efforts to do so.</p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/how-we-do-code-reviews-at-cloud-four/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8489</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/03/feature-code-review-r4.jpg" width="550" height="309" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/03/feature-code-review-r4.jpg" length="0" type="image/jpg" />	</item>
		<item>
		<title>Getting Your Article Shared: Tips from Ten Years of Newsletter Curation</title>
		<link>https://cloudfour.com/thinks/getting-your-article-shared-tips-from-ten-years-of-newsletter-curation/</link>
					<comments>https://cloudfour.com/thinks/getting-your-article-shared-tips-from-ten-years-of-newsletter-curation/#respond</comments>
		
		<dc:creator><![CDATA[Scott Vandehey]]></dc:creator>
		<pubDate>Thu, 05 Feb 2026 16:30:00 +0000</pubDate>
				<category><![CDATA[Social]]></category>
		<category><![CDATA[newsletters]]></category>
		<category><![CDATA[opengraph]]></category>
		<category><![CDATA[promotion]]></category>
		<category><![CDATA[social]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8476</guid>

					<description><![CDATA[Some tips to make it easier to get your article shared in newsletters and social media, such as OG tags, a good sharing image, and some gotchas to watch out for.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img width="1024" height="576" src="https://cloudfour.com/wp-content/uploads/2026/02/sharing-feature-r3-1024x576.jpg" alt="Illustration of a bland grey door in a bland grey hallway, with the word “meh” on the door — which conceals the fact that on the other side of the door is a bright, colorful nature scene of a deer resting beside a waterfall — exciting content hidden behind a boring door." class="wp-image-8481" srcset="https://cloudfour.com/wp-content/uploads/2026/02/sharing-feature-r3-1024x576.jpg 1024w, https://cloudfour.com/wp-content/uploads/2026/02/sharing-feature-r3-300x169.jpg 300w, https://cloudfour.com/wp-content/uploads/2026/02/sharing-feature-r3-768x432.jpg 768w, https://cloudfour.com/wp-content/uploads/2026/02/sharing-feature-r3-1536x864.jpg 1536w, https://cloudfour.com/wp-content/uploads/2026/02/sharing-feature-r3-2048x1152.jpg 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>For over ten years now, I’ve been sharing front-end links with the community via a newsletter and social media account called <a href="https://fridayfrontend.com">Friday Front-End</a>. Every week, I bookmark 20–30 articles, and pick the best ones to include. In that time, I’ve learned some things I want to pass along to you: Recommendations to make your article more likely to be shared in newsletters and social media accounts like the one I run.</p>



<p>There’s loads of great content out there, and it’s funny how often someone puts the work into crafting an excellent post, but misses out on all the things that make it easy to widely share.</p>



<p>To understand what people like me are looking for, consider the format of a typical Friday Front-End post:</p>



<blockquote class="wp-block-quote example-social-media-post is-layout-flow wp-block-quote-is-layout-flow">
<figure class="wp-block-image size-medium"><img width="300" height="169" src="https://cloudfour.com/wp-content/uploads/2026/02/sharing-example-r1-300x169.jpg" alt="Illustration of a code editor with a cartoon-style word bubble containing “?!” as if the code editor is saying something surprising." class="wp-image-8480" srcset="https://cloudfour.com/wp-content/uploads/2026/02/sharing-example-r1-300x169.jpg 300w, https://cloudfour.com/wp-content/uploads/2026/02/sharing-example-r1-1024x576.jpg 1024w, https://cloudfour.com/wp-content/uploads/2026/02/sharing-example-r1-768x432.jpg 768w, https://cloudfour.com/wp-content/uploads/2026/02/sharing-example-r1.jpg 1280w" sizes="(max-width: 300px) 100vw, 300px" /></figure>



<p>Your Exciting Post About #CSS: “Here’s a short quote from your article to interest people to read it.” https://example.com/</p>
</blockquote>



<p>Pretty simple, right? A featured image, then the title, followed by a short quote, the URL, and a hashtag for the primary focus of the article (for Friday Front-End, this will almost always be #CSS, #JavaScript, or #a11y).</p>



<p>Now, here are the things you can do to make your post easier to share:</p>



<h2 class="wp-block-heading">Add Open Graph tags</h2>



<p>If you take just one thing from this post, make it this. Adding OG (Open Graph) tags to your post gets you the most bang for your buck. Here’s what OG tags look like:</p>


<pre class="wp-block-code"><span><code class="hljs language-handlebars"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:url"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://example.com/"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:title"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"An exciting post about CSS"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"Here's a short description of this exciting post about CSS"</span> /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">property</span>=<span class="hljs-string">"og:image"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"https://example.com/thumbnail.jpg"</span> /&gt;</span></span></code></span></pre>


<p>There are more tags you could use, but you get the idea. In a nutshell, a long time ago, Facebook came up with a standard for describing your web page so their crawlers could understand it. They used that information to make little preview cards of a link when someone shared your page. The concept spread quickly, and now pretty much every social network out there will use your OG tags to make a preview card.</p>



<p>Even better, tools that people like me use to manage their social media accounts and newsletters, like <a href="https://buffer.com">Buffer</a> or <a href="https://www.curated.co">Curated</a>, also understand them. That means I can simply pass them your post’s URL, and they automatically extract useful information like the title and thumbnail, which makes my job much easier.</p>



<h3 class="wp-block-heading">Note: add Open Graph tags about your post, not your site</h3>



<p>A surprisingly common problem I run into is a great post that does have OG tags, but they describe the person’s <em>site</em> as a whole, rather than the individual <em>post</em> I’m trying to share. This might feel better than nothing, but it actually backfires because when I share the link to your post, the preview card might show information about your site, rather than the actual post. (e.g., “Sandra’s Awesome CSS Blog” vs “An Exciting Post About CSS.”). If the goal of the preview card is to convince readers to click through, then you definitely want the card to show information about your post, not your site as a whole.</p>



<h3 class="wp-block-heading">Learn more about Open Graph tags:</h3>



<ul class="wp-block-list">
<li><a href="https://ogp.me">Open Graph specification</a></li>



<li><a href="https://indieweb.org/The-Open-Graph-protocol">IndieWeb Open Graph documentation</a></li>



<li><a href="https://developer.yoast.com/features/opengraph/functional-specification/">Yoast SEO Open Graph documentation</a></li>



<li><a href="https://cloudfour.com/thinks/how-we-added-open-graph-tags-to-cloudfour-com/">How We Added Open Graph Tags to CloudFour.com</a></li>
</ul>



<h2 class="wp-block-heading">Add a sharing image</h2>



<p>A well-chosen sharing image can be the perfect teaser for your post, something that catches the audience’s attention and makes them want to click through to learn more. If you have a great sharing image, it absolutely increases the likelihood that I will share your post, and that readers will click through.</p>



<p>However, I understand not everyone is lucky enough to work with a talented cartoonist like my coworker Tyler, who has created some of the best sharing images here on Cloud Four. If that’s the case for you, I recommend a visit to <a href="https://unsplash.com">Unsplash</a>, which has an excellent collection of free images that you can use for your sharing image, often just for the cost of giving the creator an image credit at the bottom of your post.</p>



<p>Another increasingly common approach is to automatically generate sharing images for your posts by creating an image of the post’s title. This is better than no sharing image, but unless they’ve got a bit of design flair, it can feel bland or even repetitive, since the post title will usually be displayed near the post thumbnail in the preview card.</p>



<p>One thing I see people do that is actually <em>worse</em> than providing no sharing image is to use a single sharing image for every page on your site, typically the site logo or a big photo of yourself. When readers see these seemingly random images in the preview card for your post, it can feel unintentional.</p>



<p>And to be clear, I’m not saying that a hand-crafted illustration is always better than a stock photo or a generated title card. For example, A stock photo of a footpath worn in the grass of a public space for a post about <a href="https://www.w3.org/TR/html-design-principles/#pave-the-cowpaths">“paving the cowpaths”</a> for user accessibility is great. A stock photo of a boat anchor on a post about CSS anchor positioning is less interesting.</p>



<p>Here’s <a href="https://ia.net/topics/is-every-picture-worth-1000-words">some excellent advice on choosing stock photos</a> for your post.</p>



<h2 class="wp-block-heading">Use a descriptive title</h2>



<p>It’s always frustrating to share a well-written post with a title that communicates nothing about the topic of the post. Let me give you an example with two titles for a hypothetical post about the flexibility of CSS custom properties to allow users to override your theme’s default colors:</p>



<ul class="wp-block-list">
<li>You Can Go Your Own Way</li>



<li>How to Empower Developers with Custom Properties</li>
</ul>



<p>I understand if you feel the second title is bland or even boring. But you know what it does well? It tells me what the post is about. The first example might be clever in context, but if I can’t understand it until after I’ve read the post, then it’s failing to convince me to read in the first place.</p>



<h2 class="wp-block-heading">Add a blurb</h2>



<p>Something I love, and will often copy directly into Friday Front-End posts, is when the author provides a TL;DR (Too Long; Didn’t Read) summary at the top of the post. Call it whatever you want: a blurb, a description, an excerpt, or a summary. The point is that it’s a short, punchy description that summarizes your post and convinces me to read.</p>



<p>There’s a sweet spot for length. Too short, and you won’t communicate enough. Too long, and I’ll just have to trim it to make it fit in a social media post. Here are two extreme examples:</p>



<ul class="wp-block-list">
<li>How to override theme colors with custom properties.</li>



<li>CSS custom properties are a powerful tool that can empower developers and users alike. In this article, I’m going to show you how to make your theme fully customizable through the use of custom properties, discuss their limitations, explore browser support, and encourage you to adopt this fantastic tool into your arsenal.</li>
</ul>



<p>The first is certainly an efficient description of the post topic. But it’s actually too short. There’s nothing there to convince me to read it. The second, on the other hand, is too verbose. I get distracted before I even finish reading it.</p>



<p>As a rule of thumb, I like to aim for 140 characters —&nbsp;a completely arbitrary length that happens to be half the length of a post on a certain social media site I don’t use anymore. That’s short enough to be easy to share in a social media post (along with the title and URL), but long enough to be able to tease the contents of the post.</p>



<h2 class="wp-block-heading">Use canonical URLs properly</h2>



<p>Okay, this one’s getting into the weeds a bit, but it’s something to check on your site. Some CMS tools will automatically add a canonical URL tag. This is really useful if you have a post with multiple valid URLs, or if you’re syndicating content from one site to another, and want to make sure all the SEO traffic goes to the original site.</p>


<pre class="wp-block-code"><span><code class="hljs language-handlebars"><span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"canonical"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://example.com"</span>&gt;</span></span></code></span></pre>


<p>However, a surprisingly common problem I see is that a post will have a canonical URL tag that points to the <em>homepage</em> of the site rather than the <em>post</em> itself. This is an insidious issue because you can still go to the URL directly, but tools that understand the canonical URL will link to the wrong place.</p>



<p>I’m particularly aware of this because some of the tools I use to save links, like <a href="https://www.instapaper.com/">Instapaper</a>, will save the canonical URL if one is available. Which means when I go to review my links later, what’s actually been saved is a seemingly random link to someone’s homepage. If I’m lucky, I can skim their recent posts and remember the title of the post I tried to save, but sometimes I can’t figure it out, and their post doesn’t get shared.</p>



<p>So, please take a moment to view the source on one of your posts and, if you see a canonical URL tag, make sure it’s pointing to the correct URL.</p>



<h2 class="wp-block-heading">Add a date</h2>



<p>This last tip is perhaps more specific to the front-end industry, but since web technologies change so quickly, it’s important to know that you’re not unintentionally sharing some out-of-date information. If you show the date your post was published somewhere, it’s easy for me to check that I’m not accidentally linking to something written a long time ago, which may no longer be valid.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Putting out a weekly newsletter means I’m in the unusual position of getting a high-level overview of the most popular web development content being shared every week. It means I can spot some trends, see what people are interested in (or struggling with). It also means I see a wide variety of sites and how well they interact with common social media sharing tools. I hope this list of tips helps you avoid putting a lot of work into writing a post, only to see it struggle for views because it’s not easy to share.</p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/getting-your-article-shared-tips-from-ten-years-of-newsletter-curation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8476</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/02/sharing-feature-r3.jpg" width="550" height="309" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/02/sharing-feature-r3.jpg" length="0" type="image/jpg" />	</item>
		<item>
		<title>Faking a Fieldset-Legend</title>
		<link>https://cloudfour.com/thinks/faking-a-fieldset-legend/</link>
					<comments>https://cloudfour.com/thinks/faking-a-fieldset-legend/#respond</comments>
		
		<dc:creator><![CDATA[Tyler Sticka]]></dc:creator>
		<pubDate>Tue, 20 Jan 2026 16:56:45 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Development]]></category>
		<guid isPermaLink="false">https://cloudfour.com/?p=8460</guid>

					<description><![CDATA[Using CSS to make a heading overlay and clip the border of its own container.]]></description>
										<content:encoded><![CDATA[
<p>My buddy <a href="https://chriskirknielsen.com/">Christopher Kirk-Nielsen</a> wanted to mimic the look of a <code>&lt;legend></code> inside a <code>&lt;fieldset></code> for a section of a blog post: Specifically, the way the <code>&lt;legend></code> element magically overlays and partially clips the border of the containing <code>&lt;fieldset></code>.</p>



<p>Chris posed this challenge <a href="https://front-end.social/@chriskirknielsen/115692516298506089">on Mastodon</a>, where <a href="https://social.lol/@tylersticka/115696450792695179">I suggested a solution</a> he ended up building upon for <a href="https://chriskirknielsen.com/blog/yearnotes-2025/">his 2025 Yearnotes</a>.</p>



<p>Here&#8217;s a refined version of the demo I shared:</p>



<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_wBGNpbg" src="//codepen.io/anon/embed/wBGNpbg?height=450&amp;theme-id=1&amp;slug-hash=wBGNpbg&amp;default-tab=result" height="450" scrolling="no" frameborder="0" allowfullscreen allowpaymentrequest name="CodePen Embed wBGNpbg" title="CodePen Embed wBGNpbg" class="cp_embed_iframe" style="width:100%;overflow:hidden">CodePen Embed Fallback</iframe></div>



<p>A few details I&#8217;m proud of:</p>



<ul class="wp-block-list">
<li>It&#8217;s actually transparent (backgrounds show through)</li>



<li>The border remains middle-aligned with the &#8220;legend,&#8221; even when it breaks to multiple lines</li>



<li>You can easily tweak its appearance via CSS custom properties</li>
</ul>



<p>So, how&#8217;s it work?</p>



<h2 class="wp-block-heading">HTML</h2>



<p>Our markup consists of three elements:</p>



<ul class="wp-block-list">
<li>An outer container (our fake <code>&lt;fieldset&gt;</code>)</li>



<li>A heading (our fake <code>&lt;legend&gt;</code>)</li>



<li>A wrapper for the inner content</li>
</ul>


<pre class="wp-block-code"><span><code class="hljs language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"legendary"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>This is not a fieldset<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- content --&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></code></span></pre>


<p>A few quick notes:</p>



<ul class="wp-block-list">
<li>This pattern won&#8217;t rely on specific elements. You should use whatever containers, heading levels, etc. make the most semantic sense for your use case.</li>



<li>The inner content wrapper may not be necessary if you&#8217;re willing to accept some compromises. (More on this <a href="#variations">later</a>.)</li>



<li>I stole the excellent class name from Mr. Kirk-Nielsen&#8217;s implementation. Thanks, Chris!</li>
</ul>



<h2 class="wp-block-heading">CSS</h2>



<p>Instead of struggling to overlay the &#8220;legend&#8221; while clipping the border beneath, we&#8217;re going to <a href="https://en.wikipedia.org/wiki/Slicing_(interface_design)">slice</a> the containing shape into three chunks: One for either side of our legend, and one for everything below.</p>



<img src="https://cloudfour.com/wp-content/uploads/2026/01/fieldset-legend-sketch.png" alt="Hand-drawn sketch of the intended layout, with pencil lines marking slices for the northwest and northeast corners in addition to legend and content elements" style="display: block; margin-inline: auto; inline-size: 100%; max-inline-size: 620px;" width="930" height="430"/>



<p>We already have elements for our legend and lower content section. To avoid cluttering the markup, we&#8217;ll use pseudo elements to represent the &#8220;northwest&#8221; and &#8220;northeast&#8221; slices.</p>



<p>First, let&#8217;s translate our sketch to a CSS Grid. I like to use <code>grid-template-areas</code> to make a little text-based representation of the layout:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-class">.legendary</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-areas</span>:
    <span class="hljs-string">"nw      legend  ne"</span>
    <span class="hljs-string">"content content content"</span>;
}</code></span></pre>


<p>To keep our legend middle-aligned to the top of the adjacent borders, we&#8217;ll have it span an additional row (one earlier than the corner areas):</p>


<pre class="wp-block-code"><span><code class="hljs language-css shcb-code-table"><span class='shcb-loc'><span><span class="hljs-selector-class">.legendary</span> {
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">display</span>: grid;
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">grid-template-areas</span>:
</span></span><mark class='shcb-loc'><span>    <span class="hljs-string">".       legend  ."</span>
</span></mark><span class='shcb-loc'><span>    <span class="hljs-string">"nw      legend  ne"</span>
</span></span><span class='shcb-loc'><span>    <span class="hljs-string">"content content content"</span>;
</span></span><span class='shcb-loc'><span>}
</span></span></code></span></pre>


<p>We should also add some column and row definitions so the browser knows to divide the legend space evenly, and to stretch the northeast corner (right of the legend):</p>


<pre class="wp-block-code"><span><code class="hljs language-css shcb-code-table"><span class='shcb-loc'><span><span class="hljs-selector-class">.legendary</span> {
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">display</span>: grid;
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">grid-template-areas</span>:
</span></span><span class='shcb-loc'><span>    <span class="hljs-string">".       legend  ."</span>
</span></span><span class='shcb-loc'><span>    <span class="hljs-string">"nw      legend  ne"</span>
</span></span><span class='shcb-loc'><span>    <span class="hljs-string">"content content content"</span>;
</span></span><mark class='shcb-loc'><span>  <span class="hljs-attribute">grid-template-columns</span>:
</span></mark><mark class='shcb-loc'><span>    <span class="hljs-number">1em</span>
</span></mark><mark class='shcb-loc'><span>    auto
</span></mark><mark class='shcb-loc'><span>    <span class="hljs-built_in">minmax</span>(<span class="hljs-number">1em</span>, <span class="hljs-number">1</span>fr);
</span></mark><mark class='shcb-loc'><span>  <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr auto;
</span></mark><span class='shcb-loc'><span>}
</span></span></code></span></pre>


<p>Now we can use a <code>content</code> view to render the aforementioned pseudo elements:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-class">.legendary</span> {
  <span class="hljs-comment">/* ...  */</span>

  &amp;::before,
  &amp;::after {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
  }
}</code></span></pre>


<p>And assign the grid areas we&#8217;ve defined:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-class">.legendary</span> {
  <span class="hljs-comment">/* ...  */</span>

  &amp;::before {
    <span class="hljs-attribute">grid-area</span>: nw;
  }

  &amp;<span class="hljs-selector-pseudo">::after</span> {
    <span class="hljs-attribute">grid-area</span>: ne;
  }
  
  &gt; <span class="hljs-selector-pseudo">:first-child</span> {
    <span class="hljs-attribute">grid-area</span>: legend;
  }

  &gt; <span class="hljs-selector-pseudo">:last-child</span> {
    <span class="hljs-attribute">grid-area</span>: content;
  }
}</code></span></pre>


<p>Now for the visual appearance!</p>



<p>Since this technique hinges on coordinating the same styles across separate elements, we&#8217;ll define a few custom properties up top:</p>


<pre class="wp-block-code"><span><code class="hljs language-css"><span class="hljs-selector-class">.legendary</span> {
  <span class="hljs-attribute">--border-color</span>: currentColor;
  <span class="hljs-attribute">--border-radius</span>: <span class="hljs-number">0.25em</span>;
  <span class="hljs-attribute">--border-style</span>: solid;
  <span class="hljs-attribute">--border-width</span>: <span class="hljs-number">1px</span>;
  <span class="hljs-attribute">--legend-gap</span>: <span class="hljs-number">0.375em</span>;
  <span class="hljs-attribute">--padding</span>: <span class="hljs-number">1em</span>;

  <span class="hljs-comment">/* ... */</span>
}</code></span></pre>


<p>Which we&#8217;ll pepper throughout our final styles to draw borders and manage spacing:</p>


<pre class="wp-block-code"><span><code class="hljs language-css shcb-code-table"><span class='shcb-loc'><span><span class="hljs-selector-class">.legendary</span> {
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">--border-color</span>: currentColor;
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">--border-radius</span>: <span class="hljs-number">0.25em</span>;
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">--border-style</span>: solid;
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">--border-width</span>: <span class="hljs-number">1px</span>;
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">--legend-gap</span>: <span class="hljs-number">0.375em</span>;
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">--padding</span>: <span class="hljs-number">1em</span>;
</span></span><span class='shcb-loc'><span>
</span></span><mark class='shcb-loc'><span>  <span class="hljs-attribute">column-gap</span>: <span class="hljs-built_in">var</span>(--legend-gap);
</span></mark><span class='shcb-loc'><span>  <span class="hljs-attribute">display</span>: grid;
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">grid-template-areas</span>:
</span></span><span class='shcb-loc'><span>    <span class="hljs-string">".       legend  ."</span>
</span></span><span class='shcb-loc'><span>    <span class="hljs-string">"nw      legend  ne"</span>
</span></span><span class='shcb-loc'><span>    <span class="hljs-string">"content content content"</span>;
</span></span><span class='shcb-loc'><span>  <span class="hljs-attribute">grid-template-columns</span>:
</span></span><mark class='shcb-loc'><span>    <span class="hljs-built_in">calc</span>(var(--border-width) + <span class="hljs-built_in">var</span>(--padding) - <span class="hljs-built_in">var</span>(--legend-gap))
</span></mark><span class='shcb-loc'><span>    auto
</span></span><mark class='shcb-loc'><span>    <span class="hljs-built_in">minmax</span>(calc(var(--border-width) + <span class="hljs-built_in">var</span>(--padding) - <span class="hljs-built_in">var</span>(--legend-gap)), <span class="hljs-number">1</span>fr);
</span></mark><span class='shcb-loc'><span>  <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr auto;
</span></span><span class='shcb-loc'><span>
</span></span><mark class='shcb-loc'><span>  &amp;::before,
</span></mark><mark class='shcb-loc'><span>  &amp;::after,
</span></mark><mark class='shcb-loc'><span>  &gt; :last-child {
</span></mark><mark class='shcb-loc'><span>    <span class="hljs-attribute">border</span>: <span class="hljs-built_in">var</span>(--border-width) <span class="hljs-built_in">var</span>(--border-style) <span class="hljs-built_in">var</span>(--border-color);
</span></mark><mark class='shcb-loc'><span>  }
</span></mark><span class='shcb-loc'><span>
</span></span><span class='shcb-loc'><span>  &amp;<span class="hljs-selector-pseudo">::before</span>,
</span></span><span class='shcb-loc'><span>  &amp;<span class="hljs-selector-pseudo">::after</span> {
</span></span><mark class='shcb-loc'><span>    <span class="hljs-attribute">border-bottom-width</span>: <span class="hljs-number">0</span>;
</span></mark><span class='shcb-loc'><span>    <span class="hljs-attribute">content</span>: <span class="hljs-string">""</span>;
</span></span><span class='shcb-loc'><span>  }
</span></span><span class='shcb-loc'><span>
</span></span><span class='shcb-loc'><span>  &amp;<span class="hljs-selector-pseudo">::before</span> {
</span></span><mark class='shcb-loc'><span>    <span class="hljs-attribute">border-right-width</span>: <span class="hljs-number">0</span>;
</span></mark><mark class='shcb-loc'><span>    <span class="hljs-attribute">border-top-left-radius</span>: <span class="hljs-built_in">var</span>(--border-radius);
</span></mark><span class='shcb-loc'><span>    <span class="hljs-attribute">grid-area</span>: nw;
</span></span><span class='shcb-loc'><span>  }
</span></span><span class='shcb-loc'><span>
</span></span><span class='shcb-loc'><span>  &amp;<span class="hljs-selector-pseudo">::after</span> {
</span></span><mark class='shcb-loc'><span>    <span class="hljs-attribute">border-left-width</span>: <span class="hljs-number">0</span>;
</span></mark><mark class='shcb-loc'><span>    <span class="hljs-attribute">border-top-right-radius</span>: <span class="hljs-built_in">var</span>(--border-radius);
</span></mark><span class='shcb-loc'><span>    <span class="hljs-attribute">grid-area</span>: ne;
</span></span><span class='shcb-loc'><span>  }
</span></span><span class='shcb-loc'><span>	
</span></span><span class='shcb-loc'><span>  &gt; <span class="hljs-selector-pseudo">:first-child</span> {
</span></span><mark class='shcb-loc'><span>    <span class="hljs-attribute">font</span>: inherit;
</span></mark><span class='shcb-loc'><span>    <span class="hljs-attribute">grid-area</span>: legend;
</span></span><mark class='shcb-loc'><span>    <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
</span></mark><span class='shcb-loc'><span>  }
</span></span><span class='shcb-loc'><span>	
</span></span><span class='shcb-loc'><span>  &gt; <span class="hljs-selector-pseudo">:last-child</span> {
</span></span><mark class='shcb-loc'><span>    <span class="hljs-attribute">border-bottom-left-radius</span>: <span class="hljs-built_in">var</span>(--border-radius);
</span></mark><mark class='shcb-loc'><span>    <span class="hljs-attribute">border-bottom-right-radius</span>: <span class="hljs-built_in">var</span>(--border-radius);
</span></mark><mark class='shcb-loc'><span>    <span class="hljs-attribute">border-top-width</span>: <span class="hljs-number">0</span>;
</span></mark><span class='shcb-loc'><span>    <span class="hljs-attribute">grid-area</span>: content;
</span></span><mark class='shcb-loc'><span>    <span class="hljs-attribute">padding-top</span>: <span class="hljs-built_in">var</span>(--padding);
</span></mark><span class='shcb-loc'><span>  }
</span></span><span class='shcb-loc'><span>}
</span></span></code></span></pre>


<p>(Note the use of <code>calc</code> in the first and last columns. This keeps the main content aligned with that of the heading while taking into account gaps between the legend and border.)</p>



<h2 class="wp-block-heading">Variations</h2>



<p>Depending on the needs of your project, there may be ways to adjust or simplify this technique.</p>



<p>If your background is a flat color and known ahead of time, you can give the legend the same background and use <a href="https://cloudfour.com/thinks/faux-containers-in-css-grids/">a faux container</a> instead of separate corners:</p>



<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_PwzpqOR" src="//codepen.io/anon/embed/PwzpqOR?height=360&amp;theme-id=1&amp;slug-hash=PwzpqOR&amp;default-tab=result" height="360" scrolling="no" frameborder="0" allowfullscreen allowpaymentrequest name="CodePen Embed PwzpqOR" title="CodePen Embed PwzpqOR" class="cp_embed_iframe" style="width:100%;overflow:hidden">CodePen Embed Fallback</iframe></div>



<p>A similar trick could work for varied backgrounds if you&#8217;re willing to set <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/mix-blend-mode">a blend mode</a> (and accept any resulting color shifts):</p>



<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_GgqWJBx" src="//codepen.io/anon/embed/GgqWJBx?height=360&amp;theme-id=1&amp;slug-hash=GgqWJBx&amp;default-tab=result" height="360" scrolling="no" frameborder="0" allowfullscreen allowpaymentrequest name="CodePen Embed GgqWJBx" title="CodePen Embed GgqWJBx" class="cp_embed_iframe" style="width:100%;overflow:hidden">CodePen Embed Fallback</iframe></div>



<p>And if minimal markup is the goal, you <em>can</em> pull this off without the inner <code>&lt;div&gt;</code> element, it&#8217;ll just impose a few more constraints:</p>



<div class="wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper"><iframe id="cp_embed_WbxprQR" src="//codepen.io/anon/embed/WbxprQR?height=360&amp;theme-id=1&amp;slug-hash=WbxprQR&amp;default-tab=result" height="360" scrolling="no" frameborder="0" allowfullscreen allowpaymentrequest name="CodePen Embed WbxprQR" title="CodePen Embed WbxprQR" class="cp_embed_iframe" style="width:100%;overflow:hidden">CodePen Embed Fallback</iframe></div>



<p>We may one day get <a href="https://github.com/w3c/csswg-drafts/issues/3941">a CSS feature for mimicking <code>&lt;legend&gt;</code>’s display</a> (as pointed out by <a href="https://front-end.social/@AmeliaBR/115698173460142664">Amelia Bellamy-Royds in the original thread</a>). For now, it&#8217;s another fun excuse to solve an interesting (if <a href="https://alistapart.com/article/slidingdoors/">eerily familiar</a>) challenge with the niceties of <a href="https://cloudfour.com/topics/css/">modern CSS</a>!</p>

<hr>
<h2>We’re Cloud Four</h2>
<p>We solve complex responsive web design and development challenges for ecommerce, healthcare, fashion, B2B, SaaS, and nonprofit organizations.</p>

<p><a href="https://cloudfour.com/made/"><b>See our work</b></a></p>]]></content:encoded>
					
					<wfw:commentRss>https://cloudfour.com/thinks/faking-a-fieldset-legend/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">8460</post-id><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://cloudfour.com/wp-content/uploads/2026/01/fieldset-legend-sketch-feature-r2.jpg" width="550" height="288" medium="image" /><enclosure url="https://cloudfour.com/wp-content/uploads/2026/01/fieldset-legend-sketch-feature-r2.jpg" length="0" type="image/jpg" />	</item>
	</channel>
</rss>
