Set a Cookie with CSS

astrit profile image Astrit Updated on ・2 min read

I try to learn new stuff by creating challenges for myself and often end up becoming a full fledged project.

This time was the challenge to do a project on CSS, HTML & PHP no database, store the data on json or as flat file system just to give you some context.

Now it came the part where a cookie would solve some issues like storing the data for the user options but I did not like the fact to refresh the page just to setup a cookie.

Right at that moment I remembered:
Crooked Style Sheets - https://github.com/jbtronics/CrookedStyleSheets

This guy did a basically tracking system in CSS by using the background-image url value to call a php link where you can do whatever action you choose.

So here is what I did:

#dark-mode:checked~main [for="dark-mode"]::after {content: url('/?a=dark-mode')}

/* Previous solution looks a bit ugly but it can be set as background-image also*/ 
#dark-mode {background-image: url('/?a=dark-mode')}

Actions on php:

$action = false;

if (isset($_REQUEST['a'])) {
    $action = $_REQUEST['a'];

switch ($action) {
    case "dark-mode":
        setcookie("Dark Mode", "active", time() + (86400 * 365), "/");
    case "light":
        setcookie("Dark Mode", "", time() - 3600);
        unset($_COOKIE['Dark Mode']);

Note that I unset the cookie instead of just changing the content on case:light

The most interesting fact is when you set a cookie this way you see how the cookie will appear directly.

Based on this then I setup a conditional statement for the checkbox

 if(isset($_COOKIE['Dark Mode']) && $_COOKIE['Dark Mode'] == "active") { echo "checked" ; }

And here you are free to refresh and even close the tab with settings stored.

Basically this is just to scratch the surface but it opens doors to a lot more possibilities.

However special attention is needed on macOS Safari.

Right now is not possible to have modifiers on url() but that is subject to change at least will hope so.

Some examples:

.selector { background-image: url(/img/attr(data-bg).webp) }

Or set cookie based on attribute

.selector { content: url(/?action=attr(data-action)) }

"url-modifier" is still a experimental API


/* this works too if you want to call action on page load */
body { background-image: url(/?action=action_name) }

Thanks for reading.

Posted on Dec 22 '19 by:

astrit profile



Front-end Developer, creator of https://css.gg


markdown guide

Cute. But when does the url resolve and the cookie get set? e.g. for

#dark-mode:checked~main [for="dark-mode"]::after {content: url('/?a=dark-mode')}

is it the first time the #dark-mode element gets checked?


If I understand correctly what you said, yes the cookie is set on the first time so as soon it is checked the the cookie is set.

To unset it you could do:

#dark-mode:checked:active~main [for="dark-mode"]::after {content: url('/?a=light')}

Or if you want to play a bit more clean and you set appearance to none on input you can use the content url directly on input.

#inputId:checked::after { content: url('/?action=action-name') }


This requires the #inputId to have 
appearance:none; or -webkit-appearance:none;


Or if you feel a bit snazzy you can set the cookie even as background-image, I have tested and it works.

#dark-mode:checked {background-image: url('/?action=action-case')}