{"id":15314662,"url":"https://github.com/unframework/airtight-css-lint","last_synced_at":"2026-01-11T02:03:14.743Z","repository":{"id":57175029,"uuid":"20274393","full_name":"unframework/airtight-css-lint","owner":"unframework","description":"Check CSS for encapsulation and unwanted side-effects","archived":true,"fork":false,"pushed_at":"2017-02-27T23:01:50.000Z","size":194,"stargazers_count":9,"open_issues_count":7,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-02T15:23:51.999Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unframework.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-05-28T22:24:39.000Z","updated_at":"2023-01-28T11:49:10.000Z","dependencies_parsed_at":"2022-09-03T08:51:58.399Z","dependency_job_id":null,"html_url":"https://github.com/unframework/airtight-css-lint","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/unframework/airtight-css-lint","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unframework%2Fairtight-css-lint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unframework%2Fairtight-css-lint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unframework%2Fairtight-css-lint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unframework%2Fairtight-css-lint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unframework","download_url":"https://codeload.github.com/unframework/airtight-css-lint/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unframework%2Fairtight-css-lint/sbom","scorecard":{"id":909579,"data":{"date":"2025-08-11","repo":{"name":"github.com/unframework/airtight-css-lint","commit":"c81362efa4a73b0da0c072268912ea5bcc2295ea"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Code-Review","score":0,"reason":"Found 1/24 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"project is archived","details":["Warn: Repository is archived."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 1 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-24T18:37:48.761Z","repository_id":57175029,"created_at":"2025-08-24T18:37:48.761Z","updated_at":"2025-08-24T18:37:48.761Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28269911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-11T01:49:32.096Z","status":"online","status_checked_at":"2026-01-11T02:00:07.090Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-10-01T08:46:33.961Z","updated_at":"2026-01-11T02:03:14.714Z","avatar_url":"https://github.com/unframework.png","language":"JavaScript","readme":"[![Build Status](https://travis-ci.org/unframework/airtight-css-lint.svg?branch=master)](https://travis-ci.org/unframework/airtight-css-lint)\n\n# Airtight CSS\n\nAirtight CSS is all about CSS encapsulation to reduce side-effects/interactions between displayed elements.\n\nIt's just like [BEM](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/), but with one simple rule to fence-in components:\n\n- **each DOM element should get its style from only one place**\n\nFor every element in DOM markup, there should be *one* clearly obvious stylesheet source that influences it. The developer should also be able to trust that *no other stylesheet* ends up overriding that DOM element's appearance. Another term for this is *sole-sourced CSS*.\n\nSimple, right? It pays off surprisingly well!\n\nDue to how CSS positioning model works, that also means being careful with how absolute positioning is declared (see further below).\n\nThis linter helps enforce that guideline in the app stylesheets. That means:\n\n* CSS is grouped into composable components\n* changes/refactors have less chance of breaking neighbouring code\n* code reviews (you're doing them, right?) are less of a mind-numbing 💩 experience\n* puppies frolick and kittens play\n\n## Writing Encapsulated CSS\n\nJust like with BEM, we always work with a concept of a component class (\"block\" in BEM): e.g. `search-box` or `inline-form`. Any visual component is assumed to be a self-contained independent block of screen space.\n\nSome components may be attached to others as DOM children, but they still don't influence each other's styling, including sizing and position properties. Interplay between these visual blocks is limited to standard DOM layout flow.\n\nComponent markup might need to use child classes (\"element\" in BEM). They are always used under the umbrella of the top-level component class. To distinguish them, we either prefix them with a simple `_` (e.g. `_help-tip`), or the full top-level component name plus `__`: `search-box__help-tip`. Semantic element tags (e.g. `header`) may be used instead of a child class; anything except `div` and `span` falls under that rule.\n\nAny element might also be augmented with a modifier class (like in BEM). They are always prefixed with `-`: e.g. `-full-width`. They are always attached to either the top-level or child class.\n\nThis spells out a very clear structure for any CSS rule selector:\n\n* always start with the top-level component class selector\n* then write zero or more child class selectors or semantic tag selectors\n\nOh, and the rule may not contain another component's class name (to avoid crossing component boundaries).\n\n## Examples\n\nSimple search box example, with a help tip element and button inside (looks even nicer with LESS or SCSS nesting):\n\n```css\n.search-box {\n    position: relative;\n    display: inline-block;\n    background: #f0f0f0;\n    padding: 5px 5px 20px 5px;\n}\n\n.search-box.-full-width {\n    display: block;\n}\n\n.search-box \u003e ._help-tip {\n    position: absolute;\n    left: 5px;\n    top: 50%;\n    width: 10px;\n    height: 10px;\n    margin-top: -5px;\n}\n\n.search-box \u003e ._help-tip.-alert {\n    background: url(alert.png) 50% 50% no-repeat;\n}\n\n.search-box \u003e button {\n    border-radius: 5px;\n}\n```\n\nExamples of disallowed syntax that might cause encapsulation or ambiguity problems:\n\n```css\n/* NOPE: sidebar component stepping on the search box toes */\n.sidebar .search-box {\n    width: 100%;\n}\n\n/* NOPE: where does this even belong? */\n._cancel {\n    width: 10px;\n    height: 10px;\n}\n\n/* NOPE: should not mix semantic element tag (\"li\") with child class name (\"._title\") */\n.popup li._title {\n    background: #f00;\n}\n\n/* NOPE: non-semantic helper elements are OK, but should have a descriptive child class name like \"._content-wrapper\" */\n.popup \u003e div {\n    padding: 5px;\n}\n\n/* NOPE: using top-level class name alone (\".popup\") is distinct enough */\narticle.popup {\n    position: fixed;\n}\n```\n\n## Absolute Positioning Rules\n\nThere are also special restrictions on how absolutely-positioned elements may be declared.\n\nBrowsers place elements with `position: absolute` property based on their \"offset parent\" - either document body or a parent node with a non-static `position`. That means possibly disastrous results if, for example, a parent element mistakenly loses its `position` property: the positioned child is shifted to an unpredictable spot in the page!\n\nFor that reason, we ensure that the \"offset parent\" of a node is always defined in the same CSS component. That prevents unrelated CSS code from stepping on our toes.\n\n```css\n/* NOPE: offset parent is out of control, which means unpredictable placement */\n.search-box {\n    /* some styling... */\n}\n\n.search-box \u003e ._popup {\n    position: absolute;\n    /* some styling... */\n}\n\n/* YEP: positioning relationship is encapsulated */\n.search-box {\n    position: relative;\n    /* some styling... */\n}\n\n.search-box \u003e ._popup {\n    position: absolute;\n    /* some styling... */\n}\n```\n\n## To Do\n\n- lint actual markup as well (at runtime?)\n- document how to do e.g. code reuse and mixin styling, scenarios with DOM-based composition\n- work out fencing restrictions on CSS inheritance\n- document (lint?) margin usage hints (as another source of CSS side-effects)\n- document (lint?) LESS/SCSS specific guidelines\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funframework%2Fairtight-css-lint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funframework%2Fairtight-css-lint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funframework%2Fairtight-css-lint/lists"}