{"id":21240632,"url":"https://github.com/chrisnajman/loader","last_synced_at":"2025-03-15T03:43:41.058Z","repository":{"id":217345530,"uuid":"743637879","full_name":"chrisnajman/loader","owner":"chrisnajman","description":"CSS and JavaScript page loader which displays a loading animation or message, depending on the user's preferences.","archived":false,"fork":false,"pushed_at":"2025-03-08T17:24:11.000Z","size":14,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-08T18:24:25.605Z","etag":null,"topics":["accessibility","aria-attributes","css-imports","css-nesting","dark-mode-toggle","html-css-javascript","js-modules","prefers-reduced-motion","svg-icons","svg-sprites"],"latest_commit_sha":null,"homepage":"https://chrisnajman.github.io/loader/","language":"CSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chrisnajman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-15T16:58:54.000Z","updated_at":"2025-03-08T17:24:15.000Z","dependencies_parsed_at":"2024-11-21T02:04:03.933Z","dependency_job_id":null,"html_url":"https://github.com/chrisnajman/loader","commit_stats":null,"previous_names":["chrisnajman/loader"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisnajman%2Floader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisnajman%2Floader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisnajman%2Floader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisnajman%2Floader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chrisnajman","download_url":"https://codeload.github.com/chrisnajman/loader/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243681002,"owners_count":20330155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["accessibility","aria-attributes","css-imports","css-nesting","dark-mode-toggle","html-css-javascript","js-modules","prefers-reduced-motion","svg-icons","svg-sprites"],"created_at":"2024-11-21T00:52:13.072Z","updated_at":"2025-03-15T03:43:41.052Z","avatar_url":"https://github.com/chrisnajman.png","language":"CSS","readme":"# Loader\n\nThe loader runs until the page content is fully loaded. It is then removed from the DOM.\n\n---\n\n## Table of Contents\n\n- [Description](#description)\n- [Accessibility](#accessibility)\n  - [Screen Reader Accessibility](#screen-reader-accessibility)\n  - [User Preference: Reduced Motion](#user-preference-reduced-motion)\n  - [WAVE Web Accessibility Evaluation Tools Report](#wave-web-accessibility-evaluation-tools-report)\n- [Testing](#testing)\n  - [To Disable Animations (Chrome, Windows 10)](#to-disable-animations-chrome-windows-10)\n  - [To re-enable animations](#to-re-enable-animations)\n- [Code](#code)\n  - [HTML](#html)\n  - [CSS](#css)\n  - [JavaScript](#javascript)\n- [Source](#source)\n\n## Description\n\n- **If user-preferences allow animations**:\n  - Display loading animation.\n- **Else**:\n  - Display static text: \"Loading...\".\n\n---\n\n## Accessibility\n\n### Screen Reader Accessibility\n\nThe HTML contains text only accessible by screen readers:\n\n```HTML\n\u003cdiv id=\"loader\" class=\"loader\"\u003e\n  \u003cspan class=\"visually-hidden\"\u003eThe page is loading...\u003c/span\u003e\n\u003c/div\u003e\n\n\u003cp class=\"visually-hidden\" aria-hidden=\"true\" id=\"page-loaded\"\u003e\u003c/p\u003e\n```\n\nAfter the page has loaded (and the loader has been removed from the DOM), `p id=\"page-loaded\"` is rendered as:\n\n```HTML\n\u003cp class=\"visually-hidden\" aria-hidden=\"false\" id=\"page-loaded\"\u003eThe page has loaded.\u003c/p\u003e\n```\n\n### User Preference: Reduced Motion\n\nAll animation/transition CSS is wrapped inside:\n\n```CSS\n@media (prefers-reduced-motion: no-preference) {\n  ...\n}\n```\n\nThis ensures that if `prefers-reduced-motion` has _**not**_ been set, the animation will run.\n\nIf it _**has**_ been set, fallback CSS will display a static message.\n\n### WAVE Web Accessibility Evaluation Tools Report\n\n- [Automated accessibility analysis results](https://wave.webaim.org/report#/https://chrisnajman.github.io/loader/)\n\n---\n\n## Testing\n\nRefresh the page to trigger the loader.\n\n### To Disable Animations (Chrome, Windows 10):\n\n1. Open inspector,\n2. `Ctrl+Shift+P`,\n3. `Run\u003e`. Type 'reduce',\n4. Click 'Rendering' on 'Emulate CSS prefers-reduced-motion \u003cb\u003ereduce\u003c/b\u003e',\n5. Refresh the page.\n\n### To re-enable animations:\n\n- Follow steps 1-3 then,\n- Click 'Rendering' on 'Emulate CSS prefers-reduced-motion',\n- Refresh the page.\n\n**Tested on Windows 10 with**:\n\n- Chrome\n- Firefox\n- Microsoft Edge\n\nThe page has been tested in both browser and device views.\n\n---\n\n## Code\n\n### HTML\n\n```HTML\n\u003cdiv id=\"loader\" class=\"loader\"\u003e\n  \u003cspan class=\"visually-hidden\"\u003eThe page is loading...\u003c/span\u003e\n\u003c/div\u003e\n\n\u003cp class=\"visually-hidden\" aria-hidden=\"true\" id=\"page-loaded\"\u003e\u003c/p\u003e\n```\n\n### CSS\n\n```CSS\n:root {\n    --clr-lightest: white;\n    --clr-green: rgb(4, 167, 167);\n    --clr-dark: rgb(30, 39, 39);\n}\n\n.loader {\n    position: fixed;\n    z-index: 500;\n    inset: 0;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    background: var(--clr-dark);\n}\n\n.loader-hidden {\n    opacity: 0;\n    visibility: hidden;\n}\n\n.loader::after {\n    content: \"Loading...\";\n    font-size: 5rem;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n    .loader {\n        transition:\n            opacity 0.75s,\n            visibility 0.75s;\n    }\n\n    .loader::after {\n        content: \"\";\n        font-size: 0rem;\n        width: 10rem;\n        height: 10rem;\n        border: 2rem solid var(--clr-lightest);\n        border-top-color: var(--clr-green);\n        border-radius: 50%;\n        animation: loading 0.75s ease infinite;\n    }\n    @keyframes loading {\n        from {\n            transform: rotate(0turn);\n        }\n        to {\n            transform: rotate(1turn);\n        }\n    }\n}\n```\n\n### JavaScript\n\n```JavaScript\nwindow.addEventListener(\"load\", () =\u003e {\n  const loader = document.getElementById(\"loader\")\n  const pageLoaded = document.getElementById(\"page-loaded\")\n\n  loader.classList.add(\"loader-hidden\")\n\n  loader.addEventListener(\"transitionend\", () =\u003e {\n    loader.remove()\n\n    // For screen readers\n    pageLoaded.textContent = \"Page has loaded.\"\n    pageLoaded.setAttribute(\"aria-hidden\", \"false\")\n  })\n})\n```\n\n---\n\n## Source\n\nThis is a fork from [CSS Only Page Loader (CodePen)](https://codepen.io/dcode-software/pen/rNYGdeg), with accessibility enhancements of the CSS and JavaScript.\n\nI also made a further change to the JavaScript, replacing\n\n```JavaScript\nloader.addEventListener(\"transitionend\", () =\u003e {\n  document.body.removeChild(loader)\n})\n```\n\nwith\n\n```JavaScript\nloader.addEventListener(\"transitionend\", () =\u003e {\n  loader.remove()\n})\n```\n\nas the former triggered a console error:\n\n\u003e **Uncaught DOM Exception**: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisnajman%2Floader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchrisnajman%2Floader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisnajman%2Floader/lists"}