Make CSS do more by defining simple DOM manipulations instead of ad-hoc JavaScript.
This project implements many of the CSS selectors and rules defined in CSS3 Generated and Replaced Content Module and CSS3 Generated Content for Paged Media Module but not supported in browsers.
Some of the features are outlined below. The project has support for:
- moving content using
move-to:
- constructing stylable DOM elements using nestable
::before
,::after
, and::outside
selectors - looking up target counters and text using
target-counter(...)
andtarget-text(...)
- setting strings using
string-set:
- manipulating attributes on elements using
x-tag-name:
,x-attr:
, andx-ensure-id:
- Clickable, Floating Footnotes using several of the plugins above
- all the jQuery Selector Extensions like
:has()
,:lt()
It is easy to have the CSS Polyfills run on CSS files in the browser. Just add the following tags in <head>
:
<!-- You can include the styles inline... -->
<style type="text/x-css-polyfills">
/* Include your styles here */
</style>
<!-- OR, link to a CSS file -->
<link rel="stylesheet/css-polyfills" type="text/css" href="styles.css" />
<script src="dist.js" type="text/javascript"></script>
See examples/browser.html for an example.
The easiest way to use this repo from the command line is philschatz/css-bake.js.
You can install using npm or bower by simply running npm install css-polyfills
or bower install css-polyfills
.
Just run npm install
and then grunt
(from gruntjs.org.
::outside
: Creates a new element around the selected one (similar to::before
)::before::after
: Allows chaining of pseudoelements:footnote-call
: A marker element that remains if an element is moved elsewhere in the page:has(selector)
: Matches an element if elements inside it matchselector
(from jQuery):lt(num)
: Select all elements at an index less than index within the matched set (from jQuery):button
,:checkbox
,:eq()
,:even
,:file
,:first
,:gt()
,:has()
,:header
,:hidden
,:image
,:input
,:last
,:lt()
,:odd
,:parent
,:password
,:radio
,:reset
,:submit
,:text
(see jQuery Selector Extensions for more information)
move-to: bucket-name;
: Moves an element later in the DOMstring-set: string-name value...;
: Sets a string to be used later; wherevalue...
can include a string literal"Hello"
,attr(...)
,counter(...)
, orcontent(...)
x-ensure-id: 'attr-name';
: Ensure the element has an attribute namedattr-name
and that it contains a unique ID (useful for footnotes)x-tag-name: 'a';
: Ensure the element has a certain tag name (for making clickable pseudoelements)x-attr: attr-name value...;
: Ensure the element has a certain attribute defined (for making clickable pseudoelements)
content: pending(bucket-name);
content: string(string-name);
content: target-counter(target-id, counter-name);
content: target-text(target-id, limit);
wherelimit
can includeattr(...)
andcontent(...)
content: x-target-is(target-id, selector)
is a guard function used for labeling links based on the targetcontent(...)
: The content function as defined in CSS Generated Content for Paged Media and contains one argument which may becontents
,before
,after
,first-letter
, or a selector like"> .title"
x-sort(bucket, 'optional-selector')
: Used around thepending(...)
function to sort the elements (like for an alphabetized Glossary or Index)x-parent(...)
: Used in conjunction withattr(..)
orcontent(..)
to look up the attribute or contents of a parent element
Moving content is accomplished by move-to: bucket-name;
and content: pending(bucket-name);
as defined in CSS3 Generated and Replaced Content Module
Example:
// This element will be moved into the glossary-bucket...
.def-a { move-to: bucket-a; }
.def-b { move-to: bucket-b; }
// ... and dumped out into this area in the order added.
.area-a { content: pending(bucket-a); }
.area-b { content: pending(bucket-b); }
Browsers support simple ::before
and ::after
selectors to add a single element to the DOM.
Nestable selectors allow creating elements of arbitrary complexity.
Additionally, the ::outside
selector allows wrapping an element with another for styling.
Nested selectors and ::outside
are defined in CSS3 Generated and Replaced Content Module.
Example:
h3::before::before { content: 'Ch '; }
h3::before { content: counter(chap); }
h3::before::after { content: ': '; }
h3::outside::before { content: '[chapter starts here]'; }
Browsers support simple counters in conjunction with ::before
and ::after
for numbering tables, figures, etc.
Labeling links that use those counters is trickier. For example a link that says "See Table 4.2: Sample Dataset" is not possible to describe.
Looking up the target counter value and text in a link is simple by using target-counter(attr(href), chapter)
and target-text(attr(href))
as defined in CSS3 Generated Content for Paged Media Module.
Example:
// Just set a counter so we can look it up later
h3 { counter-increment: chap; }
h3::before { content: 'Ch ' counter(chap) ': '; }
.xref { content: 'See ' target-text(attr(href), content()); }
.xref-counter {
content: 'See Chapter ' target-counter(attr(href), chap);
}
At times it may be useful to remember a string of text and then use it later on; for example, a chapter title on the top of every page. This can be accomplished using string-set: string-name content();
and content: string(string-name);
defined in CSS3 Generated Content for Paged Media Module.
Example:
// Set a string somewhere...
h3 { string-set: chapter-title content(); }
// ... And then use it!
.chap-end { content: '[End of ' string(chapter-title) ']'; }
Using several of these extensions it is relatively straightforward to describe footnotes that move to the bottom of a page and leave a clickable link in their place (as defined in CSS3 Generated Content for Paged Media Module ).
.footnote {
// Ensure the footnote has an `id` (so we can link to it)
x-ensure-id: 'id';
// Move it to the next `footnote-area` (page end)
move-to: footnote-area;
counter-increment: footnote;
}
// The content that is left behind after the move-to
.footnote:footnote-call {
// Make the stub that is left behind a link...
x-tag-name: 'a';
// ... whose href points to the footnote.
x-attr: href '#' attr(id);
content: '[###]';
content: '[' target-counter(attr(href), footnote) ']';
}
// Place a number next to the actual footnote
.footnote::before { content: counter(footnote) ': '; }
// Define a location where the footnotes will be collected
.footnotes { content: pending(footnote-area); }
Additionally, it may be useful to define custom functions that manipulate the DOM.
For example, a sorted glossary at the end of a page can be described in CSS using move-to: glossary;
and a custom function x-sort
used in content: x-sort(pending(glossary));
.
Make sure bower
and grunt
are installed in the system by running npm install -g bower grunt
.
- Run
npm install
to install all the dependencies. - Run
npm run develop
to download bower dependencies and build thedist/css-polyfills.js
file - Host this project on a static webserver like nginx or Apache or just run
./node_modules/.bin/http-server -p 8080