[{"data":1,"prerenderedAt":336},["ShallowReactive",2],{"DefaultLayouten":3,"language-blog-slug-lights-on-or-off-i18n-slugs":134,"language-blog-slug-en-lights-on-or-off":138},{"app":4,"menu":31,"footer":66},{"githubUrl":5,"youtubeUrl":6,"linkedinUrl":7,"phoneNumber":8,"emailAddress":9,"legal":10,"addresses":20},"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002F","https:\u002F\u002Fwww.youtube.com\u002Fchannel\u002FUCzHuhQVYFRixtQN2-swcuGg","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fde-voorhoede","+31 20 2610 954","post@voorhoede.nl",[11,14,17],{"title":12,"value":13},"KvK","56017235",{"title":15,"value":16},"BTW","NL851944620B01",{"title":18,"value":19},"IBAN","NL14TRIO0320142078",[21,26],{"address":22,"city":23,"googleMapsLink":24,"postalCode":25},"Koivistokade 70","Amsterdam","https:\u002F\u002Fwww.google.com\u002Fmaps\u002Fplace\u002FDe+Voorhoede+%7C+Front-end+Development\u002F@52.396847,4.8700823,17z\u002Fdata=!3m1!4b1!4m5!3m4!1s0x47c5e21d502d2d59:0xbf570944a96ebf45!8m2!3d52.347647!4d4.8502154","1013 BB",{"address":27,"city":28,"googleMapsLink":29,"postalCode":30},"Koornmarkt 22","Delft","https:\u002F\u002Fwww.google.nl\u002Fmaps\u002Fplace\u002FKoornmarkt+22,+2611+EG+Delft\u002F@52.0093477,4.3573054,17z\u002F","2611 EG",{"title":32,"callToActions":33,"links":39},"Site Menu",[34],{"id":35,"title":36,"link":37},"163140902","Contact",{"__typename":38},"ContactRecord",[40,46,51,56,61],{"id":41,"title":42,"link":43},"163140904","Impact",{"__typename":44,"slug":45},"PageRecord","impact",{"id":47,"title":48,"link":49},"163140905","Services",{"__typename":50},"ServiceOverviewRecord",{"id":52,"title":53,"link":54},"163140906","Cases",{"__typename":55},"CaseOverviewRecord",{"id":57,"title":58,"link":59},"163140908","About us",{"__typename":44,"slug":60},"about-us",{"id":62,"title":63,"link":64},"d6WdFJq2SOuc3dWtpibbXQ","Work at",{"__typename":44,"slug":65},"work-at",{"links":67,"copyrightTitle":93,"copyrightLabel":94,"copyrightLink":95,"privacyTitle":96,"privacyLabel":97,"privacyLink":98,"certificatesGrid":99},[68,71,74,77,82,85,88],{"id":69,"title":42,"link":70},"144185264",{"__typename":44,"slug":45},{"id":72,"title":48,"link":73},"144185265",{"__typename":50},{"id":75,"title":53,"link":76},"144185266",{"__typename":55},{"id":78,"title":79,"link":80},"144185267","Blog",{"__typename":81},"BlogPostOverviewRecord",{"id":83,"title":58,"link":84},"144185268",{"__typename":44,"slug":60},{"id":86,"title":36,"link":87},"144185269",{"__typename":38},{"id":89,"title":90,"link":91},"144185270","FAQ",{"__typename":44,"slug":92},"faq","Creative Commons licence and disclaimer","CC BY 4.0","https:\u002F\u002Fcreativecommons.org\u002Flicenses\u002Fby\u002F4.0\u002F","De Voorhoede privacy statement (pdf)","Privacy statement","https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1763455455-vh-isms-006-privacy-statement-de-voorhoede-en.pdf",[100,112,123],{"id":101,"image":102,"link":107},"Xq4bBfg_TZ6Fkjax9mkbLQ",{"url":103,"alt":104,"width":105,"height":106},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353463-b-corp-logo-black-rgb.png","B Corp logo",404,680,{"__typename":108,"id":109,"title":110,"url":111},"ExternalLinkRecord","fGW1ak8XQYaYDLkBSyncog","B Corp","https:\u002F\u002Fwww.bcorporation.net\u002Fen-us\u002Ffind-a-b-corp\u002Fcompany\u002Fde-voorhoede\u002F",{"id":113,"image":114,"link":119},"c5mCXRTiSraRIB25fw1p7Q",{"url":115,"alt":116,"width":117,"height":118},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353461-dda-boxlogo-black.png","Dutch Digital Agencies logo",627,480,{"__typename":108,"id":120,"title":121,"url":122},"P6Jh7B0cTv2cKyNEeKVWVQ","Dutch Digital Agencies","https:\u002F\u002Fdutchdigitalagencies.com\u002Fleden\u002Fde-voorhoede\u002F",{"id":124,"image":125,"link":129},"MT5SCyNxSTSr_v5eeATMZw",{"url":126,"alt":127,"width":128,"height":128},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1775730283-dnv.png","DNV logo",518,{"id":130,"title":131,"link":132},"BRtNB5HnT5i-7HkA8IYzBw","DIV",{"__typename":44,"slug":133},"impact\u002Fdigitale-producten-privacy-by-design",[135],{"locale":136,"value":137},"en","lights-on-or-off",{"page":139},{"slug":137,"i18nSlugs":140,"social":142,"title":143,"subtitle":79,"isArchived":147,"headerIllustration":148,"date":149,"authors":150,"introTitle":166,"items":167,"pivots":323,"relatedBlogPosts":334,"tags":335,"onMountedScript":153,"onUnmountedScript":153},[141],{"locale":136,"value":137},{"title":143,"description":144,"image":145},"Lights on or off?","Theming experiment with CSS Dark Mode, Geolocation and the Ambient Light Sensor API. And the winner is ...",{"url":146},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1552894562-quantum-inspire-dark-mode.jpg",false,null,"2019-03-18T01:00:00.000+01:00",[151,159],{"name":152,"lastName":153,"slug":154,"image":155},"Vincent","","vincent",{"url":156,"alt":148,"width":157,"height":158},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683535345-vincent.jpg",2252,3003,{"name":160,"lastName":153,"slug":161,"image":162},"James","james",{"url":163,"alt":148,"width":164,"height":165},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534742-james.jpg",1811,2415,"Experimenting with 'dark mode' and different ways to control the theme of your website",[168,172,182,185,188,192,203,206,211,215,218,222,230,232,235,238,245,249,257,259,262,265,269,277,279,282,285,292,300,303,307,315,319],{"__typename":169,"id":170,"title":153,"body":171},"TextSectionRecord","691690","\u003Cp>In projects like \u003Ca href=\"https:\u002F\u002Fwww.quantum-inspire.com\" target=\"_blank\" rel=\"noopener\">Quantum Inspire\u003C\u002Fa> we&rsquo;ve built dark and light themes. Quantum Inspire has a dark theme editor. The docs contain the same code snippet and graph components as the editor, but now they are in a light theme:\u003C\u002Fp>",{"__typename":173,"id":174,"image":175,"caption":177,"fullWidth":180,"captionPosition":181},"ImageRecord","691691",{"url":176,"alt":177,"width":178,"height":179},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1550072159-quantuminspire.jpg","Quantum Inspire editor in dark theme and Quantum Inspire docs in light theme",1440,400,true,"bottom",{"__typename":169,"id":183,"title":153,"body":184},"691692","\u003Cp>In these projects we, as designers and developers, controlled which pages get which theme. But how can we make this contextual and give this control to our users? In this article we&rsquo;ll be experimenting with manual controls, geolocation, a new CSS feature query and the Ambient Light Sensor API.\u003C\u002Fp>",{"__typename":169,"id":186,"title":153,"body":187},"691694","\u003Cp>For our experiment we built multiple \u003Cstrong>Dark Mode\u003C\u002Fstrong> demos, each based on a different technique. We want to explore their possibilities and limitations. This helps us choose the right implementation of theming in future projects. The demos can be found \u003Ca href=\"https:\u002F\u002Fdark-mode-experiment.netlify.com\u002F\" target=\"_blank\" rel=\"noopener\">here\u003C\u002Fa>.\u003C\u002Fp>",{"__typename":169,"id":189,"title":190,"body":191},"691695","Using manual controls","\u003Cp>Let&rsquo;s start with manual controls. It&rsquo;s one of the more common approaches to themes. All we need to do to get this to work is to toggle a class. Your styling could look something like: \u003Ccode>body.theme--dark { color: #ffffff }\u003C\u002Fcode> and \u003Ccode>body.theme--light { color: #222222 }\u003C\u002Fcode>. Using \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FCSS\u002FUsing_CSS_variables\" target=\"_blank\" rel=\"noopener\">CSS custom properties\u003C\u002Fa> we can make this even more powerful.\u003C\u002Fp>\n\u003Cp>For our experiment, we created two buttons, one sets \u003Ccode>theme--dark\u003C\u002Fcode> on the \u003Ccode>&lt;body&gt;\u003C\u002Fcode> and the other \u003Ccode>theme--light\u003C\u002Fcode>. We can now write our styling using these selectors and re-assign different values to our CSS custom properties.\u003C\u002Fp>",{"__typename":193,"id":194,"mute":180,"loop":147,"autoplay":147,"caption":153,"video":195,"gif":148},"ResponsiveVideoRecord","693068",{"url":196,"title":197,"height":198,"width":199,"provider":200,"providerUid":201,"thumbnailUrl":202},"https:\u002F\u002Fvimeo.com\u002F317240749","Manual Controls - Demo",330,640,"vimeo","317240749","https:\u002F\u002Fi.vimeocdn.com\u002Fvideo\u002F759407844-4434c023f4796e10d74c45c8bae125878643de2aca78fe5b5dc4c44fb0e89e43-d_640",{"__typename":169,"id":204,"title":153,"body":205},"693069","\u003Cp>Source code (simplified):\u003C\u002Fp>",{"__typename":207,"id":208,"language":209,"body":210},"CodeBlockRecord","691696","javascript","document.getElementById('light-theme-button')\n  .addEventListener('click', setLightTheme);\ndocument.getElementById('dark-theme-button')\n  .addEventListener('click', setDarkTheme);\n\nfunction setLightTheme() {\n  document.body.classList.add('theme--light');\n  document.body.classList.remove('theme--dark');\n}\n  \nfunction setDarkTheme() {\n  document.body.classList.add('theme--dark');\n  document.body.classList.remove('theme--light');\n}",{"__typename":207,"id":212,"language":213,"body":214},"691697","css","body.theme--light { --font-color: #283444; }\nbody.theme--dark { --font-color: #ffffff; }\n\nbody.theme { color: var(--font-color); }",{"__typename":169,"id":216,"title":153,"body":217},"691700","\u003Cp>View the full \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002Fexperiment-dark-mode\u002Ftree\u002Fmaster\u002Fsrc\u002Fmanual-control\" target=\"_blank\" rel=\"noopener\">manual controls source\u003C\u002Fa>.\u003C\u002Fp>",{"__typename":169,"id":219,"title":220,"body":221},"691701","Using geolocation","\u003Cp>This is a fun one. We use the \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FGeolocation_API\" target=\"_blank\" rel=\"noopener\">Geolocation API\u003C\u002Fa> to read the user&rsquo;s latitude and longitude values. We then combine these values with a \u003Ccode>new Date()\u003C\u002Fcode> object to calculate the sunrise and sunset for the user&rsquo;s location. We used \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmourner\u002Fsuncalc\u002F\" target=\"_blank\" rel=\"noopener\">SunCalc\u003C\u002Fa> for this. Based on these values we conditionally add the \u003Ccode>theme--light\u003C\u002Fcode> or \u003Ccode>them--dark\u003C\u002Fcode> class to the body. We update these values around every minute, so we can update the user&rsquo;s location on the fly.\u003C\u002Fp>",{"__typename":193,"id":223,"mute":180,"loop":147,"autoplay":147,"caption":153,"video":224,"gif":148},"693071",{"url":225,"title":226,"height":227,"width":199,"provider":200,"providerUid":228,"thumbnailUrl":229},"https:\u002F\u002Fvimeo.com\u002F317240737","Geolocation API + Sunrise:Sunset Times - Demo",328,"317240737","https:\u002F\u002Fi.vimeocdn.com\u002Fvideo\u002F759407843-9a247064579b5993e086cc40c5b590bbf9d24c63be0e257dc55eb5fa9624b5d7-d_640",{"__typename":169,"id":231,"title":153,"body":205},"693072",{"__typename":207,"id":233,"language":209,"body":234},"693030","if ('geolocation' in navigator) {\n  navigator.geolocation.getCurrentPosition(position => {\n    const { latitude, longitude } = position.coords;\n    setInterval(() => {\n      const currentTime = new Date();\n      const { sunrise, sunset } = SunCalc.getTimes(\n        currentTime, latitude, longitude);\n      updateTheme({ currentTime, sunrise, sunset });\n    }, 60 * 1000); \u002F\u002F Update every minute.\n  });\n}\n  \nfunction updateTheme({ currentTime, sunrise, sunset }) {\n  (currentTime > sunrise && currentTime \u003C sunset)\n    ? setLightTheme()\n    : setDarkTheme();\n}",{"__typename":169,"id":236,"title":153,"body":237},"692925","\u003Cp>View the full \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002Fexperiment-dark-mode\u002Ftree\u002Fmaster\u002Fsrc\u002Fgeolocation\" target=\"_blank\" rel=\"noopener\">geolocation source\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cp>The \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FGeolocation_API#Browser_compatibility\" target=\"_blank\" rel=\"noopener\">browser support for the Geolocation API\u003C\u002Fa> is really good:\u003C\u002Fp>",{"__typename":173,"id":239,"image":240,"caption":242,"fullWidth":180,"captionPosition":181},"693043",{"url":241,"alt":242,"width":243,"height":244},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1550144768-geolocation-support.png","Geolocation browser support table",2028,944,{"__typename":169,"id":246,"title":247,"body":248},"693019","Using CSS feature query","\u003Cp>This experiment only works on MacOS Mojave, and you must use the Safari Technology Preview browser. The code itself is straightforward, and no JavaScript is required. All you need to do is to swap your theme colours inside the \u003Ccode>(prefers-color-scheme: dark)\u003C\u002Fcode> media query.\u003C\u002Fp>",{"__typename":193,"id":250,"mute":180,"loop":147,"autoplay":147,"caption":153,"video":251,"gif":148},"693077",{"url":252,"title":253,"height":254,"width":199,"provider":200,"providerUid":255,"thumbnailUrl":256},"https:\u002F\u002Fvimeo.com\u002F317240720","CSS Media Query - Demo",346,"317240720","https:\u002F\u002Fi.vimeocdn.com\u002Fvideo\u002F759407806-666e90821e88c36e7d27f842b58795558289ad4df815a805555fb746ca57ae3a-d_640",{"__typename":169,"id":258,"title":153,"body":205},"693078",{"__typename":207,"id":260,"language":213,"body":261},"693032",":root {\n  --background: #ffffff;\n  --content: #283444;\n  --content-alt: #515c6a;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    --background: #283444;\n    --content: #ffffff;\n    --content-alt: #acb8c8;\n  }\n}",{"__typename":169,"id":263,"title":153,"body":264},"693020","\u003Cp>View the full \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002Fexperiment-dark-mode\u002Ftree\u002Fmaster\u002Fsrc\u002Fmedia-query\" target=\"_blank\" rel=\"noopener\">CSS feature query source\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cp>Keep in mind that this technique has, at the time of writing, very little browser support. Hopefully this will change with the next version of Safari and other mayor browsers in the future.\u003C\u002Fp>",{"__typename":169,"id":266,"title":267,"body":268},"693021","Using ambient light sensor","\u003Cp>In our last experiment we used the ambient light sensor that is (sometimes) present on the user&rsquo;s device. Using ambient light, you could make a theme that smoothly changes depending on the current lighting conditions. Make sure you give your users an option to turn this off. Also keep in mind that this feature can be very distracting if a user is in an area where the lighting conditions often change, e.g. streets at night.\u003C\u002Fp>",{"__typename":193,"id":270,"mute":180,"loop":147,"autoplay":147,"caption":153,"video":271,"gif":148},"763944",{"url":272,"title":273,"height":274,"width":199,"provider":200,"providerUid":275,"thumbnailUrl":276},"https:\u002F\u002Fvimeo.com\u002F324209946","Ambient Light - Demo",360,"324209946","https:\u002F\u002Fi.vimeocdn.com\u002Fvideo\u002F767558310-8c863a4a8c7794908452c0f29d50dced462c9d6fbeede9f78285bee02c409687-d_640",{"__typename":169,"id":278,"title":153,"body":205},"763945",{"__typename":207,"id":280,"language":209,"body":281},"693035","if ('AmbientLightSensor' in window) {\n  const sensor = new AmbientLightSensor();\n  sensor.onreading = () => {\n    const illuminance = sensor.illuminance;\n    if (illuminance \u003C 50) {\n      setDarkTheme();\n    } else if (illuminance > 60) {\n      setLightTheme();\n    }\n  };\n  sensor.start();\n}",{"__typename":169,"id":283,"title":153,"body":284},"693022","\u003Cp>View the full \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002Fexperiment-dark-mode\u002Ftree\u002Fmaster\u002Fsrc\u002Fambient-light\" target=\"_blank\" rel=\"noopener\">ambient light sensor source\u003C\u002Fa>.\u003C\u002Fp>\n\u003Cp>As you can see below, this feature is not well supported yet. The \u003Ca href=\"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FAmbientLightSensor\" target=\"_blank\" rel=\"noopener\">AmbientLightSensor API\u003C\u002Fa> is only available in some WebKit based browsers. You also need to turn on the \u003Cem>\"Generic Sensor Extra Classes\"\u003C\u002Fem> feature flag by typing \"chrome:\u002F\u002Fflags\u002F#enable-generic-sensor-extra-classes\" into the address bar and setting it to 'enabled'. Users will be asked for permission to use the sensors. Safari is currently working on an implementation.\u003C\u002Fp>",{"__typename":173,"id":286,"image":287,"caption":289,"fullWidth":180,"captionPosition":181},"693101",{"url":288,"alt":289,"width":290,"height":291},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1550147857-ambient-light-support.png","Ambient Light support table",2024,808,{"__typename":173,"id":293,"image":294,"caption":299,"fullWidth":180,"captionPosition":181},"763966",{"url":295,"alt":296,"width":297,"height":298},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1552660607-screen-shot-2019-03-15-at-14-44-30.png","Sensor permission pop-up in a web UI",1644,1104,"Sensor permission pop-up",{"__typename":169,"id":301,"title":153,"body":302},"693023","\u003Cp>For a more in-depth guide, consider reading '\u003Ca href=\"https:\u002F\u002Fblog.arnellebalane.com\u002Fusing-the-ambient-light-sensor-api-to-add-brightness-sensitive-dark-mode-to-my-website-82223e754630\" target=\"_blank\" rel=\"noopener\">Using the Ambient Light Sensor API to add brightness-sensitive dark mode to my website\u003C\u002Fa>' by Arnelle Balane.\u003C\u002Fp>",{"__typename":169,"id":304,"title":305,"body":306},"693024","Putting Everything Together","\u003Cp>After experimenting with the mentioned techniques separately, we thought it would be interesting to put them all together into one single demo. In this video we show the 4 techniques combined in a menu. We give the user the option to select what theme they want. They can also select &lsquo;auto&rsquo;, in which case a theme is chosen based on OS settings, ambient light or their location.\u003C\u002Fp>",{"__typename":193,"id":308,"mute":180,"loop":147,"autoplay":147,"caption":153,"video":309,"gif":148},"693070",{"url":310,"title":311,"height":312,"width":199,"provider":200,"providerUid":313,"thumbnailUrl":314},"https:\u002F\u002Fvimeo.com\u002F317240708","All techniques together | demo",338,"317240708","https:\u002F\u002Fi.vimeocdn.com\u002Fvideo\u002F759407773-3a3e956963a0a90b6c92fdecee0d2ff2838fca7f6db1a4cad07d5de985b1e464-d_640",{"__typename":169,"id":316,"title":317,"body":318},"693025","Takeaways","\u003Cul>\n\u003Cli>There is a lot more involved with Dark Modes than simply inverting the colours. The process for choosing the new colours takes time, is complex and should be done by a designer. It does not only need to look right, but it also needs to be accessible.\u003C\u002Fli>\n\u003Cli>Most of the techniques used in this experiment are extremely new and not well supported. Therefore, each demo will only work on different browsers. In case you need to support every major browser, you will need to combine multiple techniques, make sure you always add Manual Controls as a fallback.\u003C\u002Fli>\n\u003Cli>While Geolocation is supported in most modern browsers, most users do not like to share their location. As an alternative, you could use the user&rsquo;s IP address estimate their approximate position.\u003C\u002Fli>\n\u003Cli>The \u003Ccode>AmbientLightSensor\u003C\u002Fcode> API does not seem to work on the newer MacBooks. We weren&rsquo;t able to figure out if this is a MacOS Mojave bug or if the API does not support the True Tone Sensor that&rsquo;s commonly used in Apple devices.\u003C\u002Fli>\n\u003C\u002Ful>",{"__typename":169,"id":320,"title":321,"body":322},"693026","Conclusion","\u003Cp>We should embrace the fact that &lsquo;dark modes&rsquo; will show up in more and more places. Users should be able to decide how they want to experience your content. While most of the techniques mentioned above are quite new and not very well supported, some can be used right now. We do suggest you always provide some form of manual control or the ability to completely turn off dark mode. Some users might prefer the lighter theme.\u003C\u002Fp>\n\u003Cp>You can find the code for all the experiments in the following \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002Fexperiment-dark-mode\" target=\"_blank\" rel=\"noopener\">repository\u003C\u002Fa>&nbsp;or you can \u003Ca href=\"https:\u002F\u002Fdark-mode-experiment.netlify.com\u002F\" target=\"_blank\" rel=\"noopener\">play with the demos\u003C\u002Fa> yourself.\u003C\u002Fp>",[324],{"title":325,"body":326,"links":327,"mailchimpValue":153,"mailchimpName":153,"mailchimpId":153,"formType":153,"contactPerson":148},"Also in love with the web?","\u003Cp>For us, that’s about technology and user experience. Fast, available for all, enjoyable to use. And fun to build. This is how our team bands together, adhering to the same values, to make sure we achieve a solid result for clients both large and small. Does that fit you?\u003C\u002Fp>\n",[328],{"__typename":329,"id":330,"title":331,"link":332},"InternalLinkRecord","163140992","Join our team",{"__typename":44,"slug":333},"jobs",[],[],1776256143446]