1<!doctype html><html lang=en-GB class="h-100 overflow-x-hidden" data-bs-theme=dark>
2<script>(function(){var theme=localStorage.getItem("data-bs-theme");theme&&document.documentElement.setAttribute("data-bs-theme",theme)})()</script>
2<meta charset=utf-8> 3<meta name=viewport content="width=device-width"> 4<title>Christian Oliff</title> 5<link rel=monetization href=https://ilp.gatehub.net/959499052/eur> 6<link rel=stylesheet href=/css/style.min.css?v0.166.0> 7<link rel=preload href=/fonts/roboto-v47-latin-500.woff2 as=font type=font/woff2 crossorigin> 8<link rel=preload href=/fonts/roboto-v47-latin-regular.woff2 as=font type=font/woff2 crossorigin><link rel=preload as=image href=/img/header/header-factory.svg fetchpriority=high><link rel="alternate icon" href=/favicon.ico type=image/x-icon sizes=any> 9<link rel=icon href=/favicon.svg type=image/svg+xml>
10<script type=module async src=/js/invoker.min.js></script>
vendor: 1 bytes, line 10
10
11<script type=speculationrules> 12{ 13 "prerender": [{ 14 "where": { 15 "href_matches": "/*" 16 }, 17 "eagerness": "moderate" 18 }] 19} 20</script>
vendor: 1 bytes, line 20
20
21<script src=/js/scroll-to-top.min.js?v0.166.0 defer></script>
vendor: 1 bytes, line 21
21
22<script src=/js/button-sound.min.js?v0.166.0 defer></script>
vendor: 1 bytes, line 22
22
23<script src=/js/code-copy.min.js?v0.166.0 defer></script>
23 24<meta name=description content="Online Adventures of a Front-End Web Developer"> 25<meta property="og:url" content="https://christianoliff.com/"> 26<meta property="og:site_name" content="Christian Oliff"> 27<meta property="og:title" content="Christian Oliff"> 28<meta property="og:description" content="Online Adventures of a Front-End Web Developer"> 29<meta property="og:locale" content="en_GB"> 30<meta property="og:type" content="website"> 31<meta property="og:image" content="https://christianoliff.com/img/header/header-factory.png"> 32<meta property="og:updated_time" content="2026-09-23T11:20:47+00:00"> 33<meta name=fediverse:creator content="@[email protected]"> 34<meta name=theme-color content="#04B9EE"><link rel=canonical href="https://christianoliff.com/?pt=378206&ct=christianoliffcom&mt=8"> 35<link rel=alternate type=application/rss+xml href=https://christianoliff.com/feed.xml title="Christian Oliff"> 36<link rel=stylesheet href=https://cdn.jsdelivr.net/npm/[email protected]/css/bootstrap-forced-colors.min.css media="screen and (forced-colors: active)"> 37<link rel=webmention href=https://webmention.io/christianoliff.com/webmention> 38<link rel=pingback href=https://webmention.io/christianoliff.com/xmlrpc> 39<meta name=monetization content="$ilp.uphold.com/Epqzn3YGr2MB"> 40<meta name=color-scheme content="dark light"> 41<meta name=generator content="Hugo 0.166.0">
42<script defer src=https://eu.umami.is/script.js data-website-id=c032a7d1-8357-44f5-aa1e-9424c2d29705></script>
42 43<body class="d-flex flex-column min-vh-100 overflow-x-hidden" id=listjs-body data-url=/ data-bs-no-jquery><div class="skippy overflow-hidden visually-hidden"> 44<div class=container> 45<a class="sr-only sr-only-focusable nav-item mt-3 mx-0 mx-sm-1" href=#main>Skip to 46main content</a> 47</div> 48</div> 49<header class="container-fluid container-header px-0" style=background-color:#04b9ee;background-image:url(/img/header/header-factory.svg)> 50<div class="container-fluid px-0"> 51<div class=container-navbar><nav class="navbar navbar-expand pt-0 mb-n2 navbar-dark" id=mainNav> 52<div class="container flex-row"> 53<a class=navbar-brand href=/> // Christian Oliff </a> 54<ul class="navbar-nav ms-auto"> 55<li class=nav-item> 56<button type=button class="nav-link border-0" commandfor=modalSettings command=show-modal aria-label=info><svg width="16" height="16" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196.0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627.0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627.0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627.0 12 5.373 12 12v1e2h12c6.627.0 12 5.373 12 12v24z"/></svg></button> 57</ul> 58</div> 59</nav> 60</div> 61<div class="bg-angle-white px-0 mt-0">
62<script src=/js/bootstrap.bundle.min.js fetchpriority=low></script>
62 63</div> 64</div> 65</header> 66<main class=flex-grow-1><div id=main class="mt-n5 pt-1 pt-sm-2"> 67<div class=container-fluid> 68<div class="container rounded pb-5 bg-body pt-2"><div class="container-xl mb-5"><h1 class="blog-posts-heading mb-4">Latest blog posts</h1><div class="row row-cols-1 row-cols-sm-2 mb-0"><div class=my-3> 69<article class="card card-blog-brief h-100 border-dark shadow-lg bg-black"> 70<div class="card-header top-rounded border-0 ratio" style=background-color:#eee;background-image:url(/img/header/2026/bootstrap-icons-css.png);--bs-aspect-ratio:42%> 71<div><img src=/img/header/2026/bootstrap-icons-css.png height=0 class=d-none loading=lazy alt> 72</div> 73</div> 74<div class="card-body border-0 pb-0"> 75<h2 class="card-title text-white px-2 ms-n1 h6 name">Bootstrap Icons as CSS variables</h2> 76<p class="px-2 ms-n1"> 77<a href=/blog/bootstrap-icons-css/ class="stretched-link text-decoration-none small">Use Bootstrap Icons as CSS custom properties for easy theming and inline use</a> 78</div> 79</article> 80</div><div class=my-3> 81<article class="card card-blog-brief h-100 border-dark shadow-lg bg-black"> 82<div class="card-header top-rounded border-0 ratio" style=background-color:#906b37;background-image:url(/img/header/2026/header-web-developer-tools-plus-ios-app.webp);--bs-aspect-ratio:42%> 83<div><img src=/img/header/2026/header-web-developer-tools-plus-ios-app.webp height=0 class=d-none loading=lazy alt> 84</div> 85</div> 86<div class="card-body border-0 pb-0"> 87<h2 class="card-title text-white px-2 ms-n1 h6 name">Web Developer Tools+ iOS App</h2> 88<p class="px-2 ms-n1"> 89<a href=/blog/web-developer-tools-plus-ios-app/ class="stretched-link text-decoration-none small">An iOS Safari extension for testing and debugging websites on the go</a> 90</div> 91</article> 92</div></div> 93<div class="row row-cols-1 row-cols-sm-2 row-cols-lg-3"><div class=my-3> 94<article class="card card-blog-brief h-100 border-dark shadow-lg bg-black"> 95<div class="card-header top-rounded border-0 ratio" style=background-color:#212529;background-image:url(/img/header/2025/header-bootstrap-css-breakpoint-indicator.png);--bs-aspect-ratio:42%> 96<div><img src=/img/header/2025/header-bootstrap-css-breakpoint-indicator.png height=0 class=d-none loading=lazy alt> 97</div> 98</div> 99<div class="card-body border-0 pb-0"> 100<h2 class="card-title text-white px-2 ms-n1 h6 name">Bootstrap 5 CSS Breakpoint Indicator</h2> 101<p class="px-2 ms-n1"> 102<a href=/blog/bootstrap-5-css-breakpoint-indicator/ class="stretched-link text-decoration-none small">A simple CSS snippet that displays the current Bootstrap breakpoint in your browser viewport.</a> 103</div> 104</article> 105</div><div class=my-3> 106<article class="card card-blog-brief h-100 border-dark shadow-lg bg-black"> 107<div class="card-header top-rounded border-0 ratio" style=background-color:#181b1d;background-image:url(/img/header/2025/header-bootstrap-modal-dialog.png);--bs-aspect-ratio:42%> 108<div><img src=/img/header/2025/header-bootstrap-modal-dialog.png height=0 class=d-none loading=lazy alt> 109</div> 110</div> 111<div class="card-body border-0 pb-0"> 112<h2 class="card-title text-white px-2 ms-n1 h6 name">Building a Bootstrap Modal with the dialog HTML element</h2> 113<p class="px-2 ms-n1"> 114<a href=/blog/bootstrap-modal-with-dialog/ class="stretched-link text-decoration-none small">Using with Invoker Commands - No JavaScript required</a> 115</div> 116</article> 117</div><div class=my-3> 118<article class="card card-blog-brief h-100 border-dark shadow-lg bg-black"> 119<div class="card-header top-rounded border-0 ratio" style=background-color:#ddd;background-image:url(/img/header/2025/header-image-size-info-browser-extension.png);--bs-aspect-ratio:42%> 120<div><img src=/img/header/2025/header-image-size-info-browser-extension.png height=0 class=d-none loading=lazy alt> 121</div> 122</div> 123<div class="card-body border-0 pb-0"> 124<h2 class="card-title text-white px-2 ms-n1 h6 name">Image Size Info Browser Extension</h2> 125<p class="px-2 ms-n1"> 126<a href=/blog/image-size-info-browser-extension/ class="stretched-link text-decoration-none small">I made a browser extension that shows image size information in the context menu.</a> 127</div> 128</article> 129</div></div> 130<div class="row row-cols-1 row-cols-sm-2 row-cols-lg-4"><div class=my-3> 131<article class="card card-blog-brief h-100 border-dark shadow-lg bg-black"> 132<div class="card-header top-rounded border-0 ratio" style=background-color:#ddd;background-image:url(/img/header/2023/header-bootstrap-accordion-with-detail
132s-summary.svg);--bs-aspect-ratio:42%> 133<div><img src=/img/header/2023/header-bootstrap-accordion-with-details-summary.svg height=0 class=d-none loading=lazy alt> 134</div> 135</div> 136<div class="card-body border-0 pb-0"> 137<h2 class="card-title text-white px-2 ms-n1 h6 name">Building a Bootstrap Accordion with the details/summary HTML tags in 2025</h2> 138<p class="px-2 ms-n1"> 139<a href=/blog/building-a-bootstrap-accordion-with-the-details-summary-html-tags-2025/ class="stretched-link text-decoration-none small">A collapsible accordion using `details` HTML tag and Bootstrap 5 CSS with open/close transitions</a> 140</div> 141</article> 142</div><div class=my-3> 143<article class="card card-blog-brief h-100 border-dark shadow-lg bg-black"> 144<div class="card-header top-rounded border-0 ratio" style=background-color:#253218;background-image:url(/img/header/2025/header-using-speculation-rules-to-improve-performance.svg);--bs-aspect-ratio:42%> 145<div><img src=/img/header/2025/header-using-speculation-rules-to-improve-performance.svg height=0 class=d-none loading=lazy alt> 146</div> 147</div> 148<div class="card-body border-0 pb-0"> 149<h2 class="card-title text-white px-2 ms-n1 h6 name">Using the Speculation Rules API to Improve Performance</h2> 150<p class="px-2 ms-n1"> 151<a href=/blog/using-speculation-rules-to-improve-performance/ class="stretched-link text-decoration-none small">Prerender pages on hover using the HTML speculation rules API</a> 152</div> 153</article> 154</div><div class=my-3> 155<article class="card card-blog-brief h-100 border-dark shadow-lg bg-black"> 156<div class="card-header top-rounded border-0 ratio" style=background-color:#19191a;background-image:url(/img/header/2025/header-safari-wishlist-2025.svg);--bs-aspect-ratio:42%> 157<div><img src=/img/header/2025/header-safari-wishlist-2025.svg height=0 class=d-none loading=lazy alt> 158</div> 159</div> 160<div class="card-body border-0 pb-0"> 161<h2 class="card-title text-white px-2 ms-n1 h6 name">Safari Wishlist (2025)</h2> 162<p class="px-2 ms-n1"> 163<a href=/blog/safari-wishlist-2025/ class="stretched-link text-decoration-none small">My top 10 wishes for Safari in 2025.</a> 164</div> 165</article> 166</div><div class=my-3> 167<article class="card card-blog-brief h-100 border-dark shadow-lg bg-black"> 168<div class="card-header top-rounded border-0 ratio" style=background-color:#e5ebf0;background-image:url(/img/header/2025/header-bootstrap-javascript-snippets.svg);--bs-aspect-ratio:42%> 169<div><img src=/img/header/2025/header-bootstrap-javascript-snippets.svg height=0 class=d-none loading=lazy alt> 170</div> 171</div> 172<div class="card-body border-0 pb-0"> 173<h2 class="card-title text-white px-2 ms-n1 h6 name">Bootstrap JavaScript Snippets</h2> 174<p class="px-2 ms-n1"> 175<a href=/blog/bootstrap-javascript-snippets/ class="stretched-link text-decoration-none small">Helpful little code snippets for web developers to enhance usability and accessibility.</a> 176</div> 177</article> 178</div></div><div class="text-center mt-3"> 179<a href=/blog/ class="h6 text-light"> 180View All 181</a> 182</div></div> 183</div> 184</div> 185</div></main><footer class="container-fluid pt-2"> 186<div class=container> 187<div class="row py-2"> 188<div class=col-12> 189<a href=https://github.com/coliff target=_blank rel=me class="me-4 link-g"><svg width="16" height="16" class="me-1 mt-n1" viewBox="0 0 496 512"><path fill="currentColor" d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6.0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6.0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3.0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1.0-6.2-.3-40.4-.3-61.4.0.0-70 15-84.7-29.8.0.0-11.4-29.1-27.8-36.6.0.0-22.9-15.7 1.6-15.4.0.0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5.0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9.0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4.0 33.7-.3 75.4-.3 83.6.0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6.0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9.0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>GitHub</a> 190<br class="d-block d-sm-none"> 191<a href=https://www.linkedin.com/in/christianoliff/ target=_blank rel=me class="me-4 link-l">
191<svg width="16" height="16" class="me-1 mt-n1" viewBox="0 0 448 512"><path fill="currentColor" d="M416 32H31.9C14.3 32 0 46.5.0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6.0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3.0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2.0 38.5 17.3 38.5 38.5.0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6.0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2.0 79.7 44.3 79.7 101.9V416z"/></svg>LinkedIn</a> 192<a href=https://mastodon.social/@christianoliff target=_blank rel=me class="me-4 link-m"><svg width="16" height="16" class="me-1 mt-n1" viewBox="0 0 448 512"><path fill="currentColor" d="M433 179.11c0-97.2-63.71-125.7-63.71-125.7-62.52-28.7-228.56-28.4-290.48.0.0.0-63.72 28.5-63.72 125.7.0 115.7-6.6 259.4 105.63 289.1 40.51 10.7 75.32 13 103.33 11.4 50.81-2.8 79.32-18.1 79.32-18.1l-1.7-36.9s-36.31 11.4-77.12 10.1c-40.41-1.4-83-4.4-89.63-54a102.54 102.54.0 01-.9-13.9c85.63 20.9 158.65 9.1 178.75 6.7 56.12-6.7 105-41.3 111.23-72.9 9.8-49.8 9-121.5 9-121.5zm-75.12 125.2h-46.63v-114.2c0-49.7-64-51.6-64 6.9v62.5h-46.33V197c0-58.5-64-56.6-64-6.9v114.2H90.19c0-122.1-5.2-147.9 18.41-175 25.9-28.9 79.82-30.8 103.83 6.1l11.6 19.5 11.6-19.5c24.11-37.1 78.12-34.8 103.83-6.1 23.71 27.3 18.4 53 18.4 175z"/></svg>Mastodon</a> 193<a href=https://bsky.app/profile/christianoliff.com target=_blank rel=me class="me-4 link-b"><svg width="16" height="16" class="me-1 mt-n1" viewBox="0 0 600 530"><path fill="currentColor" d="m135.72 44.03C202.216 93.951 273.74 195.17 3e2 249.49c26.262-54.316 97.782-155.54 164.28-205.46C512.26 8.009 590-19.862 590 68.825c0 17.712-10.155 148.79-16.111 170.07-20.703 73.984-96.144 92.854-163.25 81.433 117.3 19.964 147.14 86.092 82.697 152.22-122.39 125.59-175.91-31.511-189.63-71.766-2.514-7.3797-3.6904-10.832-3.7077-7.8964-.0174-2.9357-1.1937.51669-3.7077 7.8964-13.714 40.255-67.233 197.36-189.63 71.766-64.444-66.128-34.605-132.26 82.697-152.22-67.108 11.421-142.55-7.4491-163.25-81.433-5.9562-21.282-16.111-152.36-16.111-170.07.0-88.687 77.742-60.816 125.72-24.795z"/></svg> 194Bluesky</a> 195<a href=/feed.xml class="me-4 link-r"><svg width="16" height="16" class="me-1 mt-n1" viewBox="0 0 448 512"><path fill="currentColor" d="M4e2 32H48C21.49 32 0 53.49.0 80v352c0 26.51 21.49 48 48 48h352c26.51.0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM112 416c-26.51.0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm157.533.0h-34.335c-6.011.0-11.051-4.636-11.442-10.634-5.214-80.05-69.243-143.92-149.123-149.123-5.997-.39-10.633-5.431-10.633-11.441v-34.335c0-6.535 5.468-11.777 11.994-11.425 110.546 5.974 198.997 94.536 204.964 204.964.352 6.526-4.89 11.994-11.425 11.994zm103.027.0h-34.334c-6.161.0-11.175-4.882-11.427-11.038-5.598-136.535-115.204-246.161-251.76-251.76C68.882 152.949 64 147.935 64 141.774V107.44c0-6.454 5.338-11.664 11.787-11.432 167.83 6.025 302.21 141.191 308.205 308.205.232 6.449-4.978 11.787-11.432 11.787z"/></svg>RSS Feed</a> 196</div> 197</div> 198<div class="row py-2"> 199<div class=col-12> 200<p class="small opacity-50"> 201© 2026 Christian Oliff.<br class="d-block d-sm-none"> 202<span>Powered by 203<a href=https://getbootstrap.com target=_blank rel=noopener class=opacity-75>Bootstrap</a> / 204<a href=https://gohugo.io target=_blank rel=noopener class=opacity-75>Hugo</a> / 205<a href=https://github.com/ target=_blank rel=noopener class=opacity-75>GitHub</a> / 206<a href=https://www.cloudflare.com target=_blank rel=noopener class=opacity-75>Cloudflare</a> / 207<button type=button data-bs-toggle=modal data-bs-target=#modalCoffee class="opacity-75 btn-text ext-link bg-transparent border-0 p-1">Coffee</button> 208</span> 209</div> 210</div> 211</div> 212</footer> 213<dialog id=modalSettings class="position-relative border-0 bg-transparent" closedby=any> 214<div class="modal d-flex position-static pt-5 mt-3"> 215<div class="modal-dialog modal-dialog-centered rounded w-100 shadow-lg"> 216<div class="modal-content modal-settings position-relative mt-2 shadow rounded"> 217<button type=button class="btn btn-close position-absolute top-0 end-0 m-2 modal-settings-close-fallback d-none" aria-label="Close settings" title=Close></button> 218<div class="modal-header border-0 text-center mx-auto mt-n4"> 219<h2 class="modal-title mx-auto text-center mt-n4"> 220<img src=/img/bio-photo.jpg srcset=/img/bio-photo.svg alt="Christian Oliff profile photo" height=122 width=122 class="mx-auto text-center rounded-circle border-white border p-1 mt-n4 bg-white d-block" loading=lazy> 221</h2> 222</div> 223<div class="modal-body text-center p-0 rounded-bottom"> 224<h4 class="text-muted mt-0 mb-4"> 225christianoliff.com 226</h4> 227<ul class="nav nav-tabs border-bottom justify-content-center" id=modalSettingsTabs role=tablist> 228<li class=nav-item role=presentation> 229<button type=button class="nav-link filter-grayscale py-1 small text-uppercase" id=modal-settings-tab data-bs-toggle=tab data-bs-target=#modal-settings-pane role=tab aria-controls=modal-settings-pane aria-selected=false> 230Settings 231</button> 232<li class=nav-item role=presentation> 233<button type=button class="nav-link active filter-grayscale py-1 small text-uppercase" id=modal-info-tab data-bs-toggle=tab data-bs-target=#modal-info-pane role=tab aria-controls=modal-info-pane aria-selected=true> 234Credits 235</button> 236<li class=nav-item role=presentation> 237<button type=button class="nav-link filter-grayscale py-1 small text-uppercase" id=modal-system-tab data-bs-toggle=tab data-bs-target=#modal-system-pane role=tab aria-controls=modal-system-pane aria-selected=false> 238System Info 239</button> 240</ul> 241<div class="tab-content text-start p-2 rounded-bottom" id=modalSettingsTabContent> 242<div class="tab-pane fade text-start px-2" id=modal-settings-pane role=tabpanel aria-labelledby=modal-settings-tab> 243<div class="d-flex flex-column gap-1"> 244<div class="form-check form-switch my-2"> 245<input class=form-check-input id=settingDarkMode type=checkbox role=switch checked switch> 246<label class=form-check-label for=settingDarkMode>Dark mode</label> 247</div> 248<div class="form-check form-switch my-1"> 249<input class=form-check-input id=settingUISounds type=checkbox role=switch switch> 250<label class=form-check-label for=settingUISounds>UI Sounds</label> 251</div> 252<div class="text-center opacity-50"> 253<hr class=my-2> 254</div> 255<div class="form-check form-switch my-2">
256<input class=form-check-input id=settingPrefersContrast type=checkbox role=switch switch> 257<label class=form-check-label for=settingPrefersContrast>Increase Contrast<br> 258<small class="text-muted mt-0 pt-0">Increase color contrast between backgrounds.</small></label> 259</div> 260<div class="form-check form-switch my-1"> 261<input class=form-check-input id=settingReduceMotion type=checkbox role=switch switch> 262<label class=form-check-label for=settingReduceMotion>Reduce Motion</label> 263</div> 264<div class="form-check form-switch my-1"> 265<input class=form-check-input id=settingReduceTransparency type=checkbox role=switch switch> 266<label class=form-check-label for=settingReduceTransparency>Reduce transparency</label> 267</div> 268</div> 269</div> 270<div class="tab-pane fade show active" id=modal-info-pane role=tabpanel aria-labelledby=modal-info-tab> 271<div class="opacity-75 my-3 text-center"> 272<h5 class="text-muted small">Built by Christian Oliff with:</h5> 273<div class=container> 274<div class="row g-1 mb-3"> 275<div class="col-4 d-flex flex-column align-items-center"> 276<svg viewBox="0 0 24 24" width="32" height="32" class="mx-auto"><path fill="currentColor" d="M11.77 11.24H9.956V8.202h2.152c1.17.0 1.834.522 1.834 1.466.0 1.008-.773 1.572-2.174 1.572zm.324 1.206H9.957v3.348h2.231c1.459.0 2.232-.585 2.232-1.685s-.795-1.663-2.326-1.663zM24 11.39v1.218c-1.128.108-1.817.944-2.226 2.268-.407 1.319-.463 2.937-.42 4.186.045 1.3-.968 2.5-2.337 2.5H4.985c-1.37.0-2.383-1.2-2.337-2.5.043-1.249-.013-2.867-.42-4.186-.41-1.324-1.1-2.16-2.228-2.268V11.39c1.128-.108 1.819-.944 2.227-2.268.408-1.319.464-2.937.42-4.186-.045-1.3.968-2.5 2.338-2.5h14.032c1.37.0 2.382 1.2 2.337 2.5-.043 1.249.013 2.867.42 4.186.409 1.324 1.098 2.16 2.226 2.268zm-7.927 2.817c0-1.354-.953-2.333-2.368-2.488v-.057c1.04-.169 1.856-1.135 1.856-2.213.0-1.537-1.213-2.538-3.062-2.538h-4.16v10.172h4.181c2.218.0 3.553-1.086 3.553-2.876z"/></svg> 277<span class="small text-muted">Bootstrap</span> 278</div> 279<div class="col-4 d-flex flex-column align-items-center"> 280<svg viewBox="0 0 500 500" width="32" height="32" class="mx-auto"><path fill="currentColor" d="M249.8 12l-61.3 175.4-186.3.6 150.9 111.6L99 479.5l152.5-107.9L408 486.1 350.6 299 5e2 187.4l-185.7.5L249.8 12"/></svg> 281<span class="small text-muted">H5BP</span> 282</div> 283<div class="col-4 d-flex flex-column align-items-center"> 284<svg viewBox="0 0 448 512" width="32" height="32" class="mx-auto"><path fill="currentColor" d="M397.8 32H50.2C22.7 32 0 54.7.0 82.2v347.6C0 457.3 22.7 480 50.2 480h347.6c27.5.0 50.2-22.7 50.2-50.2V82.2c0-27.5-22.7-50.2-50.2-50.2zm-45.4 284.3c0 4.2-3.6 6-7.8 7.8-16.7 7.2-34.6 13.7-53.8 13.7-26.9.0-39.4-16.7-71.7-16.7-23.3.0-47.8 8.4-67.5 17.3-1.2.6-2.4.6-3.6 1.2V385c0 1.8.0 3.6-.6 4.8v1.2c-2.4 8.4-10.2 14.3-19.1 14.3-11.3.0-20.3-9-20.3-20.3V166.4c-7.8-6-13.1-15.5-13.1-26.3.0-18.5 14.9-33.5 33.5-33.5 18.5.0 33.5 14.9 33.5 33.5.0 10.8-4.8 20.3-13.1 26.3v18.5c1.8-.6 3.6-1.2 5.4-2.4 18.5-7.8 40.6-14.3 61.5-14.3 22.7.0 40.6 6 60.9 13.7 4.2 1.8 8.4 2.4 13.1 2.4 22.7.0 47.8-16.1 53.8-16.1 4.8.0 9 3.6 9 7.8v140.3z"/></svg> 285<span class="small text-muted">Font Awesome</span> 286</div> 287</div> 288<div class="row g-1 mb-3"> 289<div class="col-4 d-flex flex-column align-items-center"> 290<svg viewBox="0 0 24 24" width="32" height="32" class="mx-auto"><path fill="currentColor" d="M11.754.0A3.998 3.998.0 009.705.596L3.33 4.532A4.252 4.252.0 001.313 8.147v8.03c0 1.473.79 2.838 2.067 3.574l6.486 3.733a3.88 3.88.0 003.835.018l7.043-3.966a3.817 3.817.0 001.943-3.323V7.752a3.57 3.57.0 00-1.774-3.084L13.817.541a3.998 3.998.0 00-2.063-.54zm.022 1.674c.413-.006.828.1 1.2.315l7.095 4.127c.584.34.941.96.94 1.635v8.462c0 .774-.414 1.484-1.089 1.864l-7.042 3.966a2.199 2.199.0 01-2.179-.01l-6.485-3.734a2.447 2.447.0 01-1.228-2.123v-8.03c0-.893.461-1.72 1.221-2.19l6.376-3.935a2.323 2.323.0 011.19-.347zm-4.7 3.844V18.37h2.69v-5.62h4.46v5.62h2.696V5.518h-2.696v4.681h-4.46V5.518z"/></svg> 291<span class="small text-muted">Hugo</span> 292</div> 293<div class="col-4 d-flex flex-column align-items-center"> 294<svg role="img" viewBox="0 0 24 24" width="32" height="32" class="mx-auto"><path fill="currentColor" d="M16.5088 16.8447c.1475-.5068.0908-.9707-.1553-1.3154-.2246-.3164-.6045-.499-1.0615-.5205l-8.6592-.1123a.1559.1559.0 01-.1333-.0713c-.0283-.042-.0351-.0986-.021-.1553.0278-.084.1123-.1484.2036-.1562l8.7359-.1123c1.0351-.0489 2.1601-.8868 2.5537-1.9136l.499-1.3013c.0215-.0561.0293-.1128.0147-.168-.5625-2.5463-2.835-4.4453-5.5499-4.4453-2.5039.0-4.6284 1.6177-5.3876 3.8614-.4927-.3658-1.1187-.5625-1.794-.499-1.2026.119-2.1665 1.083-2.2861 2.2856-.0283.31-.0069.6128.0635.894C1.5683 13.171.0 14.7754.0 16.752c0 .1748.0142.3515.0352.5273.0141.083.0844.1475.1689.1475h15.9814c.0909.0.1758-.0645.2032-.1553l.12-.4268zm2.7568-5.5634c-.0771.0-.1611.0-.2383.0112-.0566.0-.1054.0415-.127.0976l-.3378 1.1744c-.1475.5068-.0918.9707.1543 1.3164.2256.3164.6055.498 1.0625.5195l1.8437.1133c.0557.0.1055.0263.1329.0703.0283.043.0351.1074.0214.1562-.0283.084-.1132.1485-.204.1553l-1.921.1123c-1.041.0488-2.1582.8867-2.5527 1.914l-.1406.3585c-.0283.0713.0215.1416.0986.1416h6.5977c.0771.0.1474-.0489.169-.126.1122-.4082.1757-.837.1757-1.2803.0-2.6025-2.125-4.727-4.7344-4.727"/></svg> 295<span class="small text-muted">Cloudflare</span> 296</div> 297<div class="col-4 d-flex flex-column align-items-center">
298<svg width="32" height="32" class="mx-auto" viewBox="0 0 496 512"><path fill="currentColor" d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6.0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6.0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3.0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1.0-6.2-.3-40.4-.3-61.4.0.0-70 15-84.7-29.8.0.0-11.4-29.1-27.8-36.6.0.0-22.9-15.7 1.6-15.4.0.0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5.0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9.0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4.0 33.7-.3 75.4-.3 83.6.0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6.0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9.0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg> 299<span class="small text-muted">GitHub</span> 300</div> 301</div> 302<div class="row g-1"> 303<div class="col-4 d-flex flex-column align-items-center">
304<svg width="32" height="32" class="mx-auto" viewBox="0 0 512 512"><path fill="currentColor" d="M431.45 177.65 437.33 160h0L480 32H80A80 80 0 000 112V216a8 8 0 008 8H24a8 8 0 008-8V112A48 48 0 0180 64h26.67l32 96h0l6.05 18.16C95.41 217.9 64 277.69 64 344.62c0 51.47 18.62 84.77 49.64 117.71A57.18 57.18.0 00155.17 480H420.84a57.08 57.08.0 0041.45-17.6c31-32.95 49.69-66.24 49.71-117.72C512 278.37 481.37 217.83 431.45 177.65zM140.4 64H435.6l-32 96H172.4zm38.15 128h219.7c21 16.92 54.68 42.08 72.5 96H105.39c18.11-54 52.82-79.61 73.16-96zM439 440.45A24.92 24.92.0 01420.84 448H155.17a25 25 0 01-18.23-7.62C107.1 408.71 96 382.75 96 344.62A178.3 178.3.0 0197.9 320H478.13A180.47 180.47.0 01480 344.67c0 38.12-11.12 64.08-41 95.78z"/></svg> 305<span class="small text-muted">Coffee</span> 306</div> 307<div class="col-4 d-flex flex-column align-items-center"> 308<svg role="img" viewBox="0 0 24 24" width="32" height="32" class="mx-auto"><path fill="currentColor" d="M6.49 19.04h-.23L5.13 17.9v-.23l1.73-1.71h1.2l.15.15v1.2L6.5 19.04zM5.13 6.31V6.1l1.13-1.13h.23L8.2 6.68v1.2l-.15.15h-1.2L5.13 6.31zm9.96 9.09h-1.65l-.14-.13v-3.83c0-.68-.27-1.2-1.1-1.23-.42.0-.9.0-1.43.02l-.07.08v4.96l-.14.14H8.9l-.13-.14V8.73l.13-.14h3.7a2.6 2.6.0 012.61 2.6v4.08l-.13.14zm-8.37-2.44H.14L0 12.82v-1.64l.14-.14h6.58l.14.14v1.64l-.14.14zm17.14.0h-6.58l-.14-.14v-1.64l.14-.14h6.58l.14.14v1.64l-.14.14zM11.05 6.55V1.64l.14-.14h1.65l.14.14v4.9l-.14.14h-1.65l-.14-.13zm0 15.81v-4.9l.14-.14h1.65l.14.13v4.91l-.14.14h-1.65l-.14-.14z"/></svg> 309<span class="small text-muted">Netlify</span> 310</div> 311<div class="col-4 d-flex flex-column align-items-center"> 312<svg role="img" viewBox="0 0 24 24" width="32" height="32" class="mx-auto"><path fill="currentColor" d="M23.15 2.587 18.21.21A1.494 1.494.0 0016.505.5l-9.46 8.63-4.12-3.128a.999.999.0 00-1.276.057L.327 7.261A1 1 0 00.326 8.74L3.899 12 .326 15.26a1 1 0 00.001 1.479L1.65 17.94a.999.999.0 001.276.057l4.12-3.128 9.46 8.63a1.492 1.492.0 001.704.29l4.942-2.377A1.5 1.5.0 0024 20.06V3.939a1.5 1.5.0 00-.85-1.352zm-5.146 14.861L10.826 12l7.178-5.448v10.896z"/></svg> 313<span class="small text-muted">VS Code</span> 314</div> 315</div> 316</div> 317</div> 318<div class="my-2 text-center py-2"> 319<a href=/uses/ class="btn btn-sm btn-outline-secondary mx-2">Stuff I Use</a> 320<a href=/open-source/ class="btn btn-sm btn-outline-secondary mx-2">Open source</a> 321<a href=/contact/ class="btn btn-sm btn-outline-secondary mx-2">Contact Me</a> 322</div> 323<h6 class="small opacity-25 text-center"> 324Last updated: 2026-09-23</h6> 325</div> 326<div class="tab-pane fade text-start px-2 overflow-y-auto" id=modal-system-pane role=tabpanel aria-labelledby=modal-system-tab> 327<div class="accordion mt-2" id=systemInfoAccordion> 328<details class="accordion-item border-bottom-0" name=systemInfoAccordion> 329<summary class="accordion-button rounded-top py-1 px-2"> 330<span class="accordion-h eader user-select-none">Browser Details</span> 331</summary> 332<div class="accordion-body border-bottom p-0"> 333<table class="table table-sm table-borderless small mb-0 border-0 table-striped bg-transparent" aria-label="Browser details"> 334<tbody> 335<tr id=rowSystemBrowser> 336<th class="text-muted px-2" scope=row>Browser 337<td class=small id=systemBrowser>â 338<tr> 339<th class="text-muted px-2" scope=row>User agent 340<td class="small text-break" id=systemUserAgent>â 341<tr> 342<th class="text-muted px-2" scope=row>Platform 343<td class=small id=systemPlatform>â 344<tr> 345<th class="text-muted px-2" scope=row>Timezone 346<td class=small id=systemTimezone>â 347</table> 348</div> 349</details> 350<details class="accordion-item border-bottom-0" name=systemInfoAccordion> 351<summary class="accordion-button py-1 px-2"> 352<span class="accordion-header user-select-none">Display</span> 353</summary> 354<div class="accordion-body border-bottom p-0"> 355<table class="table table-sm table-borderless small mb-0 border-0 table-striped bg-transparent" aria-label=Display> 356<tbody> 357<tr> 358<th class="text-muted px-2" scope=row>Screen 359<td class=small id=systemScreen>â 360<tr> 361<th class="text-muted px-2" scope=row>Viewport 362<td class=small id=systemViewport>â 363<tr> 364<th class="text-muted px-2" scope=row>Pixel density 365<td class=small id=systemPixelDensity>â 366<tr> 367<th class="text-muted px-2" scope=row>Color depth 368<td class=small id=systemColorDepth>â 369<tr> 370<th class="text-muted px-2" scope=row>Orientation 371<td class=small id=systemOrientation>â 372<tr> 373<th class="text-muted px-2" scope=row>Color gamut 374<td class=small id=systemColorGamut>â 375<tr> 376<th class="text-muted px-2" scope=row>Dynamic range 377<td class=small id=systemDynamicRange>â 378</table> 379</div> 380</details> 381<details class="accordion-item border-bottom-0" name=systemInfoAccordion> 382<summary class="accordion-button py-1 px-2"> 383<span class="accordion-header user-select-none">User/System Prefs</span> 384</summary> 385<div class="accordion-body border-bottom p-0"> 386<table class="table table-sm table-borderless small mb-0 border-0 table-striped bg-transparent" aria-label="User and system preferences"> 387<tbody> 388<tr> 389<th class="text-muted px-2" scope=row>Cookies enabled 390<td class=small id=systemCookiesEnabled>â 391<tr> 392<th class="text-muted px-2" scope=row>Locale 393<td class=small id=systemLocale>â 394<tr> 395<th class="text-muted px-2" scope=row>Preferred languages 396<td class=small id=systemPreferredLanguages>â 397<tr> 398<th class="text-muted px-2" scope=row>Color scheme 399<td class=small id=systemColorScheme>â 400<tr> 401<th class="text-muted px-2" scope=row>Prefers contrast 402<td class=small id=systemPrefersContrast>â 403<tr> 404<th class="text-muted px-2" scope=row>Reduced motion 405<td class=small id=systemReducedMotion>â 406</table> 407</div> 408</details> 409<details class=accordion-item name=systemInfoAccordion id=networkAccordion> 410<summary class="accordion-button py-1 px-2"> 411<span class="accordion-header user-select-none">Network</span> 412</summary> 413<div class="accordion-body p-0"> 414<table class="table table-sm table-borderless small mb-0 border-0 table-striped bg-transparent" aria-label=Network> 415<tbody> 416<tr id=rowSystemIP> 417<th class="text-muted px-2" scope=row>IP address 418<td class=small id=systemIP>â 419<tr id=rowSystemIPVersion> 420<th class="text-muted px-2" scope=row>IP version 421<td class=small id=systemIPVersion>â 422<tr id=rowSystemISP> 423<th class="text-muted px-2" scope=row>ISP 424<td class=small id=systemISP>â 425<tr id=rowSystemLocation> 426<th class="text-muted px-2" scope=row>Location 427<td class=small id=systemLocation>â 428<tr id=rowSystemConnectionSpeed> 429<th class="text-muted px-2" scope=row>Connection speed 430<td class=small id=systemConnectionSpeed>â 431<tr id=rowSystemDownlink> 432<th class="text-muted px-2" scope=row>Downlink 433<td class=small id=systemDownlink>â 434<tr id=rowSystemRTT> 435<th class="text-muted px-2" scope=row>RTT 436<td class=small id=systemRTT>â 437<tr id=rowSystemDataSaver> 438<th class="text-muted px-2" scope=row>Data saver 439<td class=small id=systemDataSaver>â 440<tr> 441<th class="text-muted px-2" scope=row>Security 442<td class=small id=systemSecurity>â 443<tr id=rowSystemConnectionType hidden> 444<th class="text-muted px-2" scope=row>Connection type 445<td class=small id=systemConnectionType>â 446</table> 447</div> 448</details> 449</div> 450</div> 451</div> 452</div> 453</div> 454</div> 455</div> 456</dialog>
457<script src=/js/modal-settings.js defer fetchpriority=low></script>
vendor: 1 bytes, line 457
457
458<script>var tooltipTriggerList=[].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')),tooltipList=tooltipTriggerList.map(function(tooltipTriggerEl){return new bootstrap.Tooltip(tooltipTriggerEl)})</script>
458 459<div class="modal fade" tabindex=-1 id=modalCoffee aria-hidden=true> 460<div class="modal-dialog modal-dialog-centered"> 461<div class="modal-content modal-coffee shadow-lg bg-dark"> 462<div class="modal-header border-0"> 463<button type=button class="btn-close text-white" data-bs-dismiss=modal aria-label=Close> 464</button> 465</div> 466<div class="modal-body border-0"> 467<br> 468</div> 469</div> 470</div> 471</div> 472<button type=button aria-label="scroll to top" class="btn-to-top bg-dark text-white border-0 rounded position-fixed shadow"></button>
472<script type=application/ld+json> 473{ 474 "@context": "https://schema.org", 475 "@type": "WebSite", 476 "name": "Christian Oliff", 477 "url": "https:\/\/christianoliff.com\/", 478 "inLanguage":"en-GB", 479 "isFamilyFriendly": "true", 480 "description": "Online Adventures of a front-end web developer" 481} 482</script>
vendor: 1 bytes, line 482
482
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.