Merge pull request #150 from 30-seconds/from-starter

Use 30-seconds-starter template
This commit is contained in:
Angelos Chalaris
2019-08-26 13:00:07 +03:00
committed by GitHub
171 changed files with 22036 additions and 13090 deletions

View File

@ -1,3 +0,0 @@
{
"presets": ["env", "stage-2"]
}

8
.gitattributes vendored Normal file
View File

@ -0,0 +1,8 @@
src/docs/* linguist-documentation
scripts/* linguist-documentation
gatsby-browser.js linguist-documentation
gatsby-config.js linguist-documentation
gatsby-node.js linguist-documentation
gatsby-ssr.js linguist-documentation
.travis/* linguist-documentation
config.js linguist-documentation

73
.gitignore vendored
View File

@ -1,4 +1,73 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn
yarn-error.log
.pnp/
.pnp.js
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
# gatsby files
.cache/
.DS_Store
dist/
public
# Mac files
.DS_Store

View File

@ -1,16 +1,13 @@
language: node_js
node_js:
- node
install:
- npm install
script:
- npm run build
after_script:
- test $TRAVIS_EVENT_TYPE = cron
&& echo -e "\e[95mDeploying to Repository"
&& chmod +x .travis/push.sh
&& ./.travis/push.sh
- chmod +x .travis/forcepush.sh && ./.travis/forcepush.sh
cache:
directories:
- node_modules
- node_modules
node_js:
- lts/*
script:
- npm run linter
- npm run extractor
- npm run builder
after_success:
- chmod +x .travis/push.sh
- .travis/push.sh

View File

@ -1,3 +0,0 @@
if [[ $TRAVIS_COMMIT_MESSAGE == *"--force-build"* ]];
then echo -e "\e[95mFORCE-DEPLOY: Deploying to Repository" && chmod +x .travis/push.sh && ./.travis/push.sh;
fi

View File

@ -12,8 +12,10 @@ commit_website_files() {
git add *
if [ $TRAVIS_EVENT_TYPE == "cron" ]; then
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER [cron]"
elif [ $TRAVIS_EVENT_TYPE == "api" ]; then
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER [custom]"
else
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER [FORCED]"
git commit --message "Travis build: $TRAVIS_BUILD_NUMBER"
fi
fi
fi

View File

@ -1,34 +1,43 @@
### Snippet name
# Contribution guidelines
Brief description
**30 seconds of CSS** is a community effort, so feel free to contribute in any way you can. Every contribution helps!
#### HTML
Here's what you can do to help:
```html
- Submit [pull requests](https://github.com/30-seconds/30-seconds-of-css/pulls) with snippets and tests that you have created (see below for guidelines).
- [Open issues](https://github.com/30-seconds/30-seconds-of-css/issues/new) for things you want to see added or modified.
- Be part of the discussion by helping out with [existing issues](https://github.com/30-seconds/30-seconds-of-css/issues).
- Tag uncategorized snippets by adding the appropriate in the snippet's frontmatter in `tags`.
- Fix typos in existing snippets, improve snippet descriptions and explanations or provide better examples.
```
### Snippet submission and Pull request guidelines
#### CSS
```css
```
#### Demo
<!-- Leave this blank, the build script will generate the demo for you. -->
#### Explanation
<!-- Use a step-by-step (ordered) list if possible. Keep it concise. -->
#### Browser support
<!-- Use the checkmark or the warning emoji, see the existing snippets. -->
<span class="snippet__support-note">⚠️ Caveat?</span>
<!-- Whenever possible, link a `caniuse` feature which allows the browser support percentage to be displayed. -->
- https://caniuse.com/#feat=some-feature
<!-- tags: (separate each by a comma) -->
- **DO NOT MODIFY THE README.md FILE!** Make changes to individual snippet files. **Travis CI** will automatically build the `README.md` file when your pull request is merged.
- **Snippet filenames** must correspond to the title of the snippet. For example, if your snippet is titled `awesomeSnippet` the filename should be `awesomeSnippet.md`.
- Use `camelCase` or `kebab-case`, not `snake_case`.
- Avoid capitalization of words, except if the whole word is capitalized (e.g. `URL` should be capitalized in the filename and the snippet title).
- **Snippet metadata** must be included in all snippets in the form of frontmatter.
- All snippets must contain a title.
- All snippets must contain tags, prefixed with `tags:` and separated by commas (optional spaces in-between).
- Make sure the first tag in your snippet's tags is one of the main categories, as seen in the `README.md` file or the website.
- Snippet tags must include a difficulty setting (`begginer`, `intermediate` or `advanced`), preferrably at the end of the list.
- **Snippet titles** should be the same as the name of the function that is present in the snippet.
- All snippet titles must be prefixed with `title:` and be at the very first line of your snippet's frontmatter.
- Snippet titles must be unique (although if you cannot find a better title, just add some placeholder at the end of the filename and title and we will figure it out).
- Follow snippet titles with an empty line.
- **Snippet descriptions** must be short and to the point. Try to explain *what* the snippet does and *how* the snippet works and what Javascript features are used. Remember to include what functions you are using and why.
- Follow snippet descriptions with an empty line.
- **Snippet code** must be enclosed inside ` ```html `, ` ```css ` or ` ```js ` and ` ``` `.
- Remember to start your snippet's code on a new line below the opening backticks.
- Please use Javascript [Semi-Standard Style](https://github.com/Flet/semistandard).
- Try to keep your snippet's code short and to the point. Use modern techniques and features. Make sure to test your code before submitting.
- Try to make your snippet's name unique, so that it does not conflict with existing snippets.
- **Snippet explanations** should be written as lists of points, describing the implemented functionality.
- Use unordered lists if you have a few points, otherwise use an ordered list.
- If you have JavaScript functionality in your snippet, it might be worthwhile separating the explanation with it, by adding a new list or a horizontal line break (`---`).
- **Snippet browser support** should be specified as a list of links to https://www.caniuse.com/ features.
- Use the `#` next to the feature that you want in the website to get a link to it.
- Snippets should be short. If your snippet is long, you can still submit it, and we can help you shorten it or figure out ways to improve it.
- Snippets *should* solve real-world problems, no matter how simple.
- Snippets *should* be abstract enough to be applied to different scenarios.
- You can start creating a new snippet, by using the [snippet template](snippet-template.md) to format your snippets.

2421
README.md

File diff suppressed because it is too large Load Diff

4
_headers Normal file
View File

@ -0,0 +1,4 @@
[[headers]]
for = "/static/*"
[headers.values]
Cache-Control = "public, max-age=360000"

1
advanced.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="78" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect height="20" rx="3" fill="#fff" width="64"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h65v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">advanced</text><text x="325" y="140" transform="scale(.1)" textLength="530">advanced</text></g> </svg>

After

Width:  |  Height:  |  Size: 695 B

BIN
assets/30s-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
assets/NotoSans-Bold.ttf Normal file

Binary file not shown.

BIN
assets/NotoSans-Italic.ttf Normal file

Binary file not shown.

BIN
assets/NotoSans-Light.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
assets/NotoSans-Medium.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
assets/NotoSans-Regular.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 255 KiB

After

Width:  |  Height:  |  Size: 255 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/leaves1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
assets/leaves2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 KiB

18
config.js Normal file
View File

@ -0,0 +1,18 @@
module.exports = {
// Project metadata
name: `30 seconds of CSS`,
description: `A curated collection of useful CSS snippets you can understand in 30 seconds or less.`,
shortName: `30s`,
repositoryUrl: `https://github.com/30-seconds/30-seconds-of-css`,
siteUrl: `https://css.30secondsofcode.org`,
// Path information
snippetPath: `snippets`,
snippetDataPath: `snippet_data`,
assetPath: `assets`,
pagePath: `src/docs/pages`,
staticPartsPath: `src/static-parts`,
// General information
language: `css`,
secondLanguage: `html`,
optionalLanguage: `js`,
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

8
gatsby-browser.js Normal file
View File

@ -0,0 +1,8 @@
/**
* Implement Gatsby's Browser APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/browser-apis/
*/
// You can delete this file if you're not using it
export { default as wrapRootElement } from './src/docs/state/ReduxWrapper';

84
gatsby-config.js Normal file
View File

@ -0,0 +1,84 @@
const config = require('./config');
module.exports = {
siteMetadata: {
title: `${config.name}`,
description: `${config.description}`,
author: `@30-seconds`,
siteUrl: `${config.siteUrl}`,
},
plugins: [
`gatsby-plugin-sitemap`,
`gatsby-plugin-transition-link`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `snippets`,
path: `${__dirname}/${config.snippetPath}`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `snippet_data`,
path: `${__dirname}/${config.snippetDataPath}`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `assets`,
path: `${__dirname}/${config.assetPath}`,
},
},
{
resolve: `gatsby-plugin-page-creator`,
options: {
path: `${__dirname}/${config.pagePath}`,
},
},
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 590,
},
},
`gatsby-remark-prismjs`,
`gatsby-remark-copy-linked-files`,
],
},
},
`gatsby-plugin-sass`,
`gatsby-transformer-json`,
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-google-analytics`,
options: {
trackingId: `UA-117141635-1`,
anonymize: true, // Always set this to true, try to comply with GDPR out of the box
respectDNT: true, // Always set to true, be respectful of people who ask not to be tracked
cookieExpires: 0, // Always set to 0, minimum tracking for your users
},
},
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `${config.name}`,
short_name: `${config.shortName}`,
start_url: `/`,
background_color: `#1e253d`,
theme_color: `#1e253d`,
display: `standalone`,
icon: `assets/30s-icon.png`, // This path is relative to the root of the site.
},
},
`gatsby-plugin-offline`,
`gatsby-plugin-react-helmet`,
`gatsby-plugin-netlify`,
],
};

93
gatsby-node.js Normal file
View File

@ -0,0 +1,93 @@
const path = require(`path`);
const { createFilePath } = require(`gatsby-source-filesystem`);
const toKebabCase = str =>
str &&
str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.map(x => x.toLowerCase())
.join('-');
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions;
const snippetPage = path.resolve(`./src/docs/templates/SnippetPage.js`);
const tagPage = path.resolve(`./src/docs/templates/TagPage.js`);
return graphql(
`
{
allMarkdownRemark(
sort: { fields: [frontmatter___title], order: ASC }
limit: 1000
) {
edges {
node {
fields {
slug
}
frontmatter {
tags
}
fileAbsolutePath
}
}
}
}
`,
).then(result => {
if (result.errors) {
throw result.errors;
}
// Create individual snippet pages.
const snippets = result.data.allMarkdownRemark.edges;
snippets.forEach((post, index) => {
if (post.node.fileAbsolutePath.indexOf('README') !== -1)
return;
createPage({
path: `/snippet${post.node.fields.slug}`,
component: snippetPage,
context: {
slug: post.node.fields.slug,
},
});
});
// Create tag pages.
const tags = snippets.reduce((acc, post) => {
if (!post.node.frontmatter || !post.node.frontmatter.tags) return acc;
const primaryTag = post.node.frontmatter.tags.split(',')[0];
if (!acc.includes(primaryTag)) acc.push(primaryTag);
return acc;
}, []);
tags.forEach(tag => {
const tagPath = `/tag/${toKebabCase(tag)}/`;
const tagRegex = `/^\\s*${tag}/`;
createPage({
path: tagPath,
component: tagPage,
context: {
tag,
tagRegex,
},
});
});
return null;
});
};
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions;
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode });
createNodeField({
name: `slug`,
node,
value,
});
}
};

8
gatsby-ssr.js Normal file
View File

@ -0,0 +1,8 @@
/**
* Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/ssr-apis/
*/
// You can delete this file if you're not using it
export { default as wrapRootElement } from './src/docs/state/ReduxWrapper';

2901
index.html

File diff suppressed because it is too large Load Diff

6
netlify.toml Normal file
View File

@ -0,0 +1,6 @@
[build]
publish = "public"
command = "npm run webber"
[build.environment]
YARN_VERSION = "1.9.4"
YARN_FLAGS = "--no-ignore-optional"

19897
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,12 @@
"description": "A curated collection of useful CSS snippets.",
"main": "index.js",
"scripts": {
"dev": "nodemon -e md,js ./scripts/build.js & parcel index.html",
"build": "node ./scripts/build.js && npm run prettier && npm run parcel",
"parcel": "npx rimraf docs && parcel build index.html -d docs/ --public-url ./",
"prettier": "prettier --write \"**/*.{js,json,md,css,scss}\""
"builder": "node ./scripts/build.js",
"webber": "gatsby build",
"webber:dev": "gatsby develop",
"webber:serve": "gatsby serve",
"extractor": "node ./scripts/extract.js",
"linter": "prettier --write \"**/*.{js,json,md,css,scss}\""
},
"author": "atomiks",
"license": "MIT",
@ -17,26 +19,46 @@
"singleQuote": true
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-preset-env": "^1.6.1",
"babel-preset-stage-2": "^6.24.1",
"caniuse-db": "^1.0.30000813",
"date-fns": "^1.29.0",
"jsdom": "^11.6.2",
"marked": "^0.3.16",
"node-sass": "^4.9.3",
"nodemon": "^1.18.4",
"normalize.css": "^8.0.0",
"parcel-bundler": "^1.11.0",
"prettier": "^1.14.3",
"pretty": "^2.0.0",
"prismjs": "^1.11.0",
"rimraf": "^2.6.2"
},
"dependencies": {
"feather-icons": "^4.7.0",
"focus-visible": "^4.1.0",
"jump.js": "^1.0.2"
"@babel/plugin-proposal-class-properties": "^7.5.0",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/preset-env": "^7.5.4",
"@babel/preset-react": "^7.0.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"caniuse-db": "^1.0.30000989",
"front-matter": "^3.0.2",
"fs-extra": "^8.1.0",
"gatsby": "^2.12.0",
"gatsby-image": "^2.2.6",
"gatsby-plugin-google-analytics": "^2.1.6",
"gatsby-plugin-manifest": "^2.2.3",
"gatsby-plugin-netlify": "^2.1.3",
"gatsby-plugin-offline": "^2.2.4",
"gatsby-plugin-page-creator": "^2.1.5",
"gatsby-plugin-react-helmet": "^3.1.2",
"gatsby-plugin-sass": "^2.1.3",
"gatsby-plugin-sharp": "^2.2.7",
"gatsby-plugin-sitemap": "^2.2.8",
"gatsby-plugin-transition-link": "^1.12.4",
"gatsby-remark-copy-linked-files": "^2.1.3",
"gatsby-remark-images": "^3.1.6",
"gatsby-remark-prismjs": "^3.3.3",
"gatsby-source-filesystem": "^2.1.5",
"gatsby-transformer-json": "^2.2.2",
"gatsby-transformer-remark": "^2.6.6",
"gatsby-transformer-sharp": "^2.2.3",
"gsap": "^2.1.3",
"kleur": "^3.0.3",
"markdown-builder": "^0.9.0",
"node-sass": "^4.12.0",
"prettier": "^1.18.2",
"prismjs": "^1.16.0",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-copy-to-clipboard": "^5.0.1",
"react-css-transition-replace": "^3.0.3",
"react-dom": "^16.8.6",
"react-helmet": "^5.2.1",
"react-redux": "^7.1.0",
"redux": "^4.0.4"
}
}

View File

@ -1,177 +1,142 @@
const fs = require('fs')
const path = require('path')
const marked = require('marked')
const pretty = require('pretty')
const caniuseDb = require('caniuse-db/data.json')
const sass = require('node-sass')
const { toKebabCase, createElement, template, dom, getCode } = require('../utils/utils.js')
const { differenceInDays } = require('date-fns')
/*
This is the builder script that generates the README file.
Run using `npm run builder`.
*/
// Load modules
const fs = require('fs-extra');
const path = require('path');
const { green, red } = require('kleur');
const util = require('./util');
const markdown = require('markdown-builder');
const { headers, misc, lists } = markdown;
const config = require('../config');
const SNIPPETS_PATH = './snippets'
const TAGS = [
{
name: 'all',
icon: 'check'
},
{
name: 'layout',
icon: 'layout'
},
{
name: 'visual',
icon: 'eye'
},
{
name: 'animation',
icon: 'loader'
},
{
name: 'interactivity',
icon: 'edit-2'
},
{
name: 'other',
icon: 'tag'
}
]
// Paths (relative to package.json)
const SNIPPETS_PATH = `./${config.snippetPath}`;
const STATIC_PARTS_PATH = `./${config.staticPartsPath}`;
const renderer = new marked.Renderer()
renderer.heading = (text, level) => {
if (level === 3) {
return `<h${level} id="${toKebabCase(text)}"><span>${text}</span></h${level}>`
} else {
return ['HTML', 'CSS', 'JavaScript'].includes(text)
? `<h${level} data-type="${text}">${text}</h${level}>`
: `<h${level}>${text}</h${level}>`
}
}
renderer.link = (url, _, text) => `<a href="${url}" target="_blank">${text || url}</a>`
const document = dom('./src/html/index.html')
const components = {
backToTopButton: dom('./src/html/components/back-to-top-button.html'),
sidebar: dom('./src/html/components/sidebar.html'),
header: dom('./src/html/components/header.html'),
main: dom('./src/html/components/main.html'),
tags: dom('./src/html/components/tags.html')
// Terminate if parent commit is a Travis build
if (
util.isTravisCI() &&
/^Travis build: \d+/g.test(process.env['TRAVIS_COMMIT_MESSAGE'])
) {
console.log(
`${green(
'NOBUILD',
)} README build terminated, parent commit is a Travis build!`,
);
process.exit(0);
}
const snippetContainer = components.main.querySelector('.container')
const sidebarLinkContainer = components.sidebar.querySelector('.sidebar__links')
TAGS.slice(1).forEach(tag => {
sidebarLinkContainer.append(
createElement(`
<section data-type="${tag.name}" class="sidebar__section">
<h4 class="sidebar__section-heading">${tag.name}</h4>
</section>
`)
)
})
// Setup everything
let snippets = {},
snippetsArray = [],
startPart = '',
endPart = '',
output = '';
const EMOJIS = {};
for (const snippetFile of fs.readdirSync(SNIPPETS_PATH)) {
const snippetPath = path.join(SNIPPETS_PATH, snippetFile)
const snippetData = fs.readFileSync(snippetPath, 'utf8')
console.time('Builder');
const html = getCode('html', snippetData).trim()
const css = getCode('css', snippetData)
const scopedCSS = sass.renderSync({
data: `[data-scope="${snippetFile}"] { ${css} }`
})
const js = getCode('js', snippetData)
// Synchronously read all snippets from snippets folder and sort them as necessary (case-insensitive)
snippets = util.readSnippets(SNIPPETS_PATH);
snippetsArray = Object.keys(snippets).reduce((acc, key) => {
acc.push(snippets[key]);
return acc;
}, []);
const demo =
`<div class="snippet-demo" data-scope="${snippetFile}">${html}</div>` +
`<style>${scopedCSS.css.toString()}</style>` +
`${js ? `<script>(function(){${js}})();</script>` : ''}`
// Load static parts for the README file
try {
startPart = fs.readFileSync(
path.join(STATIC_PARTS_PATH, 'README-start.md'),
'utf8',
);
endPart = fs.readFileSync(
path.join(STATIC_PARTS_PATH, 'README-end.md'),
'utf8',
);
} catch (err) {
console.log(`${red('ERROR!')} During static part loading: ${err}`);
process.exit(1);
}
const markdown = marked(snippetData, { renderer }).replace(
'<h4>Demo</h4>',
`<h4>Demo</h4>${demo}`
)
const snippetEl = createElement(`<div class="snippet">${markdown}</div>`)
snippetContainer.append(snippetEl)
// Create the output for the README file
try {
const tags = util.prepTaggedData(
Object.keys(snippets).reduce((acc, key) => {
acc[key] = snippets[key].attributes.tags;
return acc;
}, {}),
);
// browser support usage
const featUsageShares = (snippetData.match(/https?:\/\/caniuse\.com\/#feat=.*/g) || []).map(
feat => {
const featData = caniuseDb.data[feat.match(/#feat=(.*)/)[1]]
// caniuse doesn't count "untracked" users, which makes the overall share appear much lower
// than it probably is. Most of these untracked browsers probably support these features.
// Currently it's around 5.3% untracked, so we'll use 4% as probably supporting the feature.
// Also the npm package appears to be show higher usage % than the main website, this shows
// about 0.2% lower than the main website when selecting "tracked users" (as of Feb 2019).
const UNTRACKED_PERCENT = 4
const usage = featData
? Number(featData.usage_perc_y + featData.usage_perc_a) + UNTRACKED_PERCENT
: 100
return Math.min(100, usage)
output += `${startPart}\n`;
// Loop over tags and snippets to create the table of contents
for (const tag of tags) {
const capitalizedTag = util.capitalize(tag, true);
const taggedSnippets = snippetsArray.filter(
snippet => snippet.attributes.tags[0] === tag,
);
output += headers.h3((EMOJIS[tag] || '') + ' ' + capitalizedTag).trim();
output +=
misc.collapsible(
'View contents',
lists.ul(taggedSnippets, snippet =>
misc.link(
`\`${snippet.title}\``,
`${misc.anchor(snippet.title)}${
snippet.attributes.tags.includes('advanced') ? '-' : ''
}`,
),
),
) + '\n';
}
for (const tag of tags) {
const capitalizedTag = util.capitalize(tag, true);
const taggedSnippets = snippetsArray.filter(
snippet => snippet.attributes.tags[0] === tag,
);
output +=
misc.hr() + headers.h2((EMOJIS[tag] || '') + ' ' + capitalizedTag) + '\n';
for (let snippet of taggedSnippets) {
if (snippet.attributes.tags.includes('advanced'))
output +=
headers.h3(
snippet.title + ' ' + misc.image('advanced', '/advanced.svg'),
) + '\n';
else output += headers.h3(snippet.title) + '\n';
output += snippet.attributes.text;
output += `\`\`\`${config.secondLanguage}\n${snippet.attributes.codeBlocks.html}\n\`\`\`\n\n`;
output += `\`\`\`${config.language}\n${snippet.attributes.codeBlocks.css}\n\`\`\`\n\n`;
if (snippet.attributes.codeBlocks.js)
output += `\`\`\`${config.optionalLanguage}\n${snippet.attributes.codeBlocks.js}\n\`\`\`\n\n`;
output += headers.h4('Explanation');
output += snippet.attributes.explanation;
output += headers.h4('Browser support') + '\n';
output += snippet.attributes.browserSupport.supportPercentage.toFixed(1) + '%';
output += snippet.attributes.browserSupport.text;
output +=
'\n<br>' + misc.link('⬆ Back to top', misc.anchor('Contents')) + '\n';
}
)
const browserSupportHeading = snippetEl.querySelector('h4:last-of-type')
browserSupportHeading.after(
createElement(`
<div>
<div class="snippet__browser-support">
${featUsageShares.length ? Math.min(...featUsageShares).toPrecision(3) : 100}%
</div>
</div>
`)
)
// sidebar link
const link = createElement(
`<a class="sidebar__link" href="#${snippetFile.replace('.md', '')}">${
snippetEl.querySelector('h3').innerHTML
}</a>`
)
// new icon = less than 31 days old
const date = (snippetData.match(/<!--\s*date:\s*(.+?)-->/) || [, ''])[1]
if (date && differenceInDays(new Date(), new Date(date)) < 31) {
const newIcon = '<img alt="New" draggable="false" class="snippet__new" src="./src/img/new.svg">'
snippetEl.prepend(createElement(newIcon))
link.prepend(createElement(newIcon))
}
// tags
const tags = (snippetData.match(/<!--\s*tags:\s*(.+?)-->/) || [, ''])[1]
.split(/,\s*/)
.forEach(tag => {
tag = tag.trim().toLowerCase()
snippetEl
.querySelector('h3')
.append(
createElement(
`<span class="tags__tag snippet__tag" data-type="${tag}"><i data-feather="${
TAGS.find(t => t.name === tag).icon
}"></i>${tag}</span>`
)
)
sidebarLinkContainer.querySelector(`section[data-type="${tag}"]`).append(link)
})
// Add the ending static part
output += `\n${endPart}\n`;
// Write to the README file
fs.writeFileSync('README.md', output);
} catch (err) {
console.log(`${red('ERROR!')} During README generation: ${err}`);
process.exit(1);
}
// build dom
TAGS.forEach(tag =>
components.tags.append(
createElement(
`<button class="tags__tag is-large ${tag.name === 'all' ? 'is-active' : ''}" data-type="${
tag.name
}"><i data-feather="${tag.icon}"></i>${tag.name}</button>`
)
)
)
const content = document.querySelector('.content-wrapper')
content.before(components.backToTopButton)
content.before(components.sidebar)
content.append(components.header)
content.append(components.main)
components.main.querySelector('.container').prepend(components.tags)
// doctype declaration gets stripped, add it back in
const html = `<!DOCTYPE html>
${pretty(document.documentElement.outerHTML, { ocd: true })}
`
fs.writeFileSync('./index.html', html)
console.log(`${green('SUCCESS!')} README file generated!`);
console.timeEnd('Builder');

80
scripts/extract.js Normal file
View File

@ -0,0 +1,80 @@
/*
This is the extractor script that generates the snippets.json file.
Run using `npm run extractor`.
*/
// Load modules
const fs = require('fs-extra');
const path = require('path');
const { green } = require('kleur');
const util = require('./util');
const config = require('../config');
// Paths (relative to package.json)
const SNIPPETS_PATH = `./${config.snippetPath}`;
const OUTPUT_PATH = `./${config.snippetDataPath}`;
// Check if running on Travis, only build for cron jobs and custom builds
if (
util.isTravisCI() &&
process.env['TRAVIS_EVENT_TYPE'] !== 'cron' &&
process.env['TRAVIS_EVENT_TYPE'] !== 'api'
) {
console.log(
`${green(
'NOBUILD',
)} snippet extraction terminated, not a cron or api build!`,
);
process.exit(0);
}
// Setup everything
let snippets = {},
snippetsArray = [];
console.time('Extractor');
// Synchronously read all snippets from snippets folder and sort them as necessary (case-insensitive)
snippets = util.readSnippets(SNIPPETS_PATH);
snippetsArray = Object.keys(snippets).reduce((acc, key) => {
acc.push(snippets[key]);
return acc;
}, []);
const completeData = {
data: [...snippetsArray],
meta: {
specification: 'http://jsonapi.org/format/',
type: 'snippetArray',
},
};
let listingData = {
data: completeData.data.map(v => ({
id: v.id,
type: 'snippetListing',
title: v.title,
attributes: {
text: v.attributes.text,
tags: v.attributes.tags,
},
meta: {
hash: v.meta.hash,
},
})),
meta: {
specification: 'http://jsonapi.org/format/',
type: 'snippetListingArray',
},
};
// Write files
fs.writeFileSync(
path.join(OUTPUT_PATH, 'snippets.json'),
JSON.stringify(completeData, null, 2),
);
fs.writeFileSync(
path.join(OUTPUT_PATH, 'snippetList.json'),
JSON.stringify(listingData, null, 2),
);
// Display messages and time
console.log(
`${green('SUCCESS!')} snippets.json and snippetList.json files generated!`,
);
console.timeEnd('Extractor');

View File

@ -0,0 +1,12 @@
// Checks if current environment is Travis CI, Cron builds, API builds
const isTravisCI = () => 'TRAVIS' in process.env && 'CI' in process.env;
const isTravisCronOrAPI = () =>
process.env['TRAVIS_EVENT_TYPE'] === 'cron' ||
process.env['TRAVIS_EVENT_TYPE'] === 'api';
const isNotTravisCronOrAPI = () => !isTravisCronOrAPI();
module.exports = {
isTravisCI,
isTravisCronOrAPI,
isNotTravisCronOrAPI,
};

60
scripts/util/helpers.js Normal file
View File

@ -0,0 +1,60 @@
const config = require('../../config');
const getMarkDownAnchor = paragraphTitle =>
paragraphTitle
.trim()
.toLowerCase()
.replace(/[^\w\- ]+/g, '')
.replace(/\s/g, '-')
.replace(/\-+$/, '');
// Creates an object from pairs
const objectFromPairs = arr => arr.reduce((a, v) => ((a[v[0]] = v[1]), a), {});
// Optimizes nodes in an HTML document
const optimizeNodes = (data, regexp, replacer) => {
let count = 0;
let output = data;
do {
output = output.replace(regexp, replacer);
count = 0;
while (regexp.exec(output) !== null) ++count;
} while (count > 0);
return output;
};
// Capitalizes the first letter of a string
const capitalize = (str, lowerRest = false) =>
str.slice(0, 1).toUpperCase() +
(lowerRest ? str.slice(1).toLowerCase() : str.slice(1));
const prepTaggedData = tagDbData =>
[...new Set(Object.entries(tagDbData).map(t => t[1][0]))]
.filter(v => v)
.sort((a, b) =>
capitalize(a, true) === 'Uncategorized'
? 1
: capitalize(b, true) === 'Uncategorized'
? -1
: a.localeCompare(b),
);
const makeExamples = data => {
data =
data.slice(0, data.lastIndexOf(`\`\`\`${config.language}`)).trim() +
misc.collapsible(
'Examples',
data.slice(
data.lastIndexOf(`\`\`\`${config.language}`),
data.lastIndexOf('```'),
) + data.slice(data.lastIndexOf('```')),
);
return `${data}\n<br>${misc.link(
'⬆ Back to top',
misc.anchor('Contents'),
)}\n\n`;
};
module.exports = {
getMarkDownAnchor,
objectFromPairs,
optimizeNodes,
capitalize,
prepTaggedData,
makeExamples,
};

37
scripts/util/index.js Normal file
View File

@ -0,0 +1,37 @@
const {
isTravisCI,
isTravisCronOrAPI,
isNotTravisCronOrAPI,
} = require('./environmentCheck');
const {
getMarkDownAnchor,
objectFromPairs,
optimizeNodes,
capitalize,
prepTaggedData,
makeExamples,
} = require('./helpers');
const {
getFilesInDir,
hashData,
getCodeBlocks,
getTextualContent,
readSnippets,
} = require('./snippetParser');
module.exports = {
isTravisCI,
isTravisCronOrAPI,
isNotTravisCronOrAPI,
getMarkDownAnchor,
objectFromPairs,
optimizeNodes,
capitalize,
prepTaggedData,
makeExamples,
getFilesInDir,
hashData,
getCodeBlocks,
getTextualContent,
readSnippets,
};

View File

@ -0,0 +1,198 @@
const fs = require('fs-extra'),
path = require('path'),
{ red } = require('kleur'),
crypto = require('crypto'),
frontmatter = require('front-matter');
const sass = require('node-sass');
const caniuseDb = require('caniuse-db/data.json');
const config = require('../../config');
// Reade all files in a directory
const getFilesInDir = (directoryPath, withPath, exclude = null) => {
try {
let directoryFilenames = fs.readdirSync(directoryPath);
directoryFilenames.sort((a, b) => {
a = a.toLowerCase();
b = b.toLowerCase();
if (a < b) return -1;
if (a > b) return 1;
return 0;
});
if (withPath) {
// a hacky way to do conditional array.map
return directoryFilenames.reduce((fileNames, fileName) => {
if (
exclude == null ||
!exclude.some(toExclude => fileName === toExclude)
)
fileNames.push(`${directoryPath}/${fileName}`);
return fileNames;
}, []);
}
return directoryFilenames.filter(v => v !== 'README.md');
} catch (err) {
console.log(`${red('ERROR!')} During snippet loading: ${err}`);
process.exit(1);
}
};
// Creates a hash for a value using the SHA-256 algorithm.
const hashData = val =>
crypto
.createHash('sha256')
.update(val)
.digest('hex');
// Gets the code blocks for a snippet file.
const getCodeBlocks = str => {
const regex = /```[.\S\s]*?```/g;
let results = [];
let m = null;
while ((m = regex.exec(str)) !== null) {
if (m.index === regex.lastIndex) regex.lastIndex += 1;
m.forEach((match, groupIndex) => {
results.push(match);
});
}
const replacer = new RegExp(
`\`\`\`${config.language}([\\s\\S]*?)\`\`\``,
'g',
);
const secondReplacer = new RegExp(
`\`\`\`${config.secondLanguage}([\\s\\S]*?)\`\`\``,
'g',
);
const optionalReplacer = new RegExp(
`\`\`\`${config.optionalLanguage}([\\s\\S]*?)\`\`\``,
'g',
);
results = results.map(v =>
v
.replace(replacer, '$1')
.replace(secondReplacer, '$1')
.replace(optionalReplacer, '$1')
.trim()
);
if (results.length > 2)
return {
html: results[0],
css: results[1],
js: results[2],
};
return {
html: results[0],
css: results[1],
js: '',
};
};
// Gets the textual content for a snippet file.
const getTextualContent = str => {
const regex = /([\s\S]*?)```/g;
const results = [];
let m = null;
while ((m = regex.exec(str)) !== null) {
if (m.index === regex.lastIndex) regex.lastIndex += 1;
m.forEach((match, groupIndex) => {
results.push(match);
});
}
return results[1].replace(/\r\n/g, '\n');
};
// Gets the explanation for a snippet file.
const getExplanation = str => {
const regex = /####\s*Explanation([\s\S]*)####/g;
const results = [];
let m = null;
while ((m = regex.exec(str)) !== null) {
if (m.index === regex.lastIndex) regex.lastIndex += 1;
m.forEach((match, groupIndex) => {
results.push(match);
});
}
// console.log(results);
return results[1].replace(/\r\n/g, '\n');
};
// Gets the browser support for a snippet file.
const getBrowserSupport = str => {
const regex = /####\s*Browser [s|S]upport([\s\S]*)/g;
const results = [];
let m = null;
while ((m = regex.exec(str)) !== null) {
if (m.index === regex.lastIndex) regex.lastIndex += 1;
m.forEach((match, groupIndex) => {
results.push(match);
});
}
let browserSupportText = results[1].replace(/\r\n/g, '\n');
const supportPercentage = (browserSupportText.match(/https?:\/\/caniuse\.com\/#feat=.*/g) || []).map(
feat => {
const featData = caniuseDb.data[feat.match(/#feat=(.*)/)[1]];
// caniuse doesn't count "untracked" users, which makes the overall share appear much lower
// than it probably is. Most of these untracked browsers probably support these features.
// Currently it's around 5.3% untracked, so we'll use 4% as probably supporting the feature.
// Also the npm package appears to be show higher usage % than the main website, this shows
// about 0.2% lower than the main website when selecting "tracked users" (as of Feb 2019).
const UNTRACKED_PERCENT = 4;
const usage = featData
? Number(featData.usage_perc_y + featData.usage_perc_a) + UNTRACKED_PERCENT
: 100;
return Math.min(100, usage);
}
)
return {
text: browserSupportText,
supportPercentage: Math.min(...supportPercentage,100)
}
};
// Synchronously read all snippets and sort them as necessary (case-insensitive)
const readSnippets = snippetsPath => {
const snippetFilenames = getFilesInDir(snippetsPath, false);
let snippets = {};
try {
for (let snippet of snippetFilenames) {
let data = frontmatter(
fs.readFileSync(path.join(snippetsPath, snippet), 'utf8'),
);
snippets[snippet] = {
id: snippet.slice(0, -3),
title: data.attributes.title,
type: 'snippet',
attributes: {
fileName: snippet,
text: getTextualContent(data.body),
explanation: getExplanation(data.body),
browserSupport: getBrowserSupport(data.body),
codeBlocks: getCodeBlocks(data.body),
tags: data.attributes.tags.split(',').map(t => t.trim()),
},
meta: {
hash: hashData(data.body),
},
};
snippets[snippet].attributes.codeBlocks.scopedCss = sass.renderSync({
data: `[data-scope="${snippets[snippet].id}"] { ${snippets[snippet].attributes.codeBlocks.css} }`
}).css.toString();
}
} catch (err) {
console.log(`${red('ERROR!')} During snippet loading: ${err}`);
process.exit(1);
}
return snippets;
};
module.exports = {
getFilesInDir,
hashData,
getCodeBlocks,
getTextualContent,
getExplanation,
getBrowserSupport,
readSnippets,
};

View File

@ -0,0 +1,658 @@
{
"data": [
{
"id": "bouncing-loader",
"type": "snippetListing",
"title": "Bouncing loader",
"attributes": {
"text": "Creates a bouncing loader animation.\n\n",
"tags": [
"animation"
]
},
"meta": {
"hash": "9ddb53b4f0d4d889f585ce69e46dc403ccd12f40dff305134bccf8b8a399bb7a"
}
},
{
"id": "box-sizing-reset",
"type": "snippetListing",
"title": "Box-sizing reset",
"attributes": {
"text": "Resets the box-model so that `width`s and `height`s are not affected by their `border`s or `padding`.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "f435b9fcc289760199b4b4781e608438b866887fa91394e94063b42f3841fab7"
}
},
{
"id": "button-border-animation",
"type": "snippetListing",
"title": "Button border animation",
"attributes": {
"text": "Creates a border animation on hover.\n\n",
"tags": [
"animation"
]
},
"meta": {
"hash": "ff6401cc784b92a9672e74968719c029de224c29fcfdc3eaeaa764274108f648"
}
},
{
"id": "calc",
"type": "snippetListing",
"title": "Calc()",
"attributes": {
"text": "The function calc() allows to define CSS values with the use of mathematical expressions, the value adopted for the property is the result of a mathematical expression.\n\n",
"tags": [
"other"
]
},
"meta": {
"hash": "dc3464c5df00866bdea869d2e02f1a3f040f97301259020828df9951de9ada8c"
}
},
{
"id": "circle",
"type": "snippetListing",
"title": "Circle",
"attributes": {
"text": "Creates a circle shape with pure CSS.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "1a068c6a0209bfd1e7155326fb219f7590193e3b81802dfecc6d705e9705adf8"
}
},
{
"id": "clearfix",
"type": "snippetListing",
"title": "Clearfix",
"attributes": {
"text": "Ensures that an element self-clears its children.\n\n###### Note: This is only useful if you are still using float to build layouts. Please consider using a modern approach with flexbox layout or grid layout.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "9479dfb4ec61a01045f480c93e21829b08017765585edbc511a653d5791e2f87"
}
},
{
"id": "constant-width-to-height-ratio",
"type": "snippetListing",
"title": "Constant width to height ratio",
"attributes": {
"text": "Given an element of variable width, it will ensure its height remains proportionate in a responsive fashion\n(i.e., its width to height ratio remains constant).\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "f94bb8368d8074d3d00ca449841b16d0fd4c4267a4abf373c43f41f2b9b6bcd1"
}
},
{
"id": "counter",
"type": "snippetListing",
"title": "Counter",
"attributes": {
"text": "Counters are, in essence, variables maintained by CSS whose values may be incremented by CSS rules to track how many times they're used.\n\n",
"tags": [
"visual",
"other"
]
},
"meta": {
"hash": "9d12a06e8dfbe67458098bb9e5fb4041a5ebd7cf5d652940ddbb8ae6f49a58dd"
}
},
{
"id": "custom-scrollbar",
"type": "snippetListing",
"title": "Custom scrollbar",
"attributes": {
"text": "Customizes the scrollbar style for the document and elements with scrollable overflow, on WebKit platforms.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "bf63836daec92d4b85128faff57480f8297c4005a25c70ee93da97bd54eaa7bf"
}
},
{
"id": "custom-text-selection",
"type": "snippetListing",
"title": "Custom text selection",
"attributes": {
"text": "Changes the styling of text selection.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "7095b8bab3e1b3736bf0b8a8a4e429d905bceaf2aec83983377d6151e9a0f660"
}
},
{
"id": "custom-variables",
"type": "snippetListing",
"title": "Custom variables",
"attributes": {
"text": "CSS variables that contain specific values to be reused throughout a document.\n\n",
"tags": [
"other"
]
},
"meta": {
"hash": "b07f694e77ae7a8c107c78aa6c4b27d1d1ef0bae5cab96a7a2fe49d48296a8aa"
}
},
{
"id": "disable-selection",
"type": "snippetListing",
"title": "Disable selection",
"attributes": {
"text": "Makes the content unselectable.\n\n",
"tags": [
"interactivity"
]
},
"meta": {
"hash": "6b99a98dfec252430da591aed665c0310b013710546c6c2d7bc4259bd7709a4a"
}
},
{
"id": "display-table-centering",
"type": "snippetListing",
"title": "Display table centering",
"attributes": {
"text": "Vertically and horizontally centers a child element within its parent element using `display: table` (as an alternative to `flexbox`).\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "08682925f9ae378097e8b3cc1d2a66f9afdcdd4bd052e2f379e03a124a1a613d"
}
},
{
"id": "donut-spinner",
"type": "snippetListing",
"title": "Donut spinner",
"attributes": {
"text": "Creates a donut spinner that can be used to indicate the loading of content.\n\n",
"tags": [
"animation"
]
},
"meta": {
"hash": "b7aa7db9756605dfa39631fd05139fb668b910030b71d5046c4149ac2d152b21"
}
},
{
"id": "dynamic-shadow",
"type": "snippetListing",
"title": "Dynamic shadow",
"attributes": {
"text": "Creates a shadow similar to `box-shadow` but based on the colors of the element itself.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "355f4fabe546f389f59a9cf08b825dca636a471a1413b753d20ea7f1f471428a"
}
},
{
"id": "easing-variables",
"type": "snippetListing",
"title": "Easing variables",
"attributes": {
"text": "Variables that can be reused for `transition-timing-function` properties, more\npowerful than the built-in `ease`, `ease-in`, `ease-out` and `ease-in-out`.\n\n",
"tags": [
"animation"
]
},
"meta": {
"hash": "48d8123982a07c883c2b8a844a1d57c0e1efb5b4f6e3e828b982c54ee8d6b6fa"
}
},
{
"id": "etched-text",
"type": "snippetListing",
"title": "Etched text",
"attributes": {
"text": "Creates an effect where text appears to be \"etched\" or engraved into the background.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "e86bdd1cef913538b157fc7fa052d989d6777be0552d9b6e9ebb474f1629d8fe"
}
},
{
"id": "evenly-distributed-children",
"type": "snippetListing",
"title": "Evenly distributed children",
"attributes": {
"text": "Evenly distributes child elements within a parent element.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "1204bc1df035e1c0d0b3808669a3a3d19201d7bc10500d8242c86fdd68a2a4d9"
}
},
{
"id": "fit-image-in-container",
"type": "snippetListing",
"title": "Fit image in container",
"attributes": {
"text": "Changes the fit and position of an image within its container while preserving its aspect ratio. Previously only possible using a background image and the `background-size` property.\n\n",
"tags": [
"layout",
"visual"
]
},
"meta": {
"hash": "5d09d5e54b7436f047db61223cff15dce2f17f6cffe5e71e0f9061337de3068e"
}
},
{
"id": "flexbox-centering",
"type": "snippetListing",
"title": "Flexbox centering",
"attributes": {
"text": "Horizontally and vertically centers a child element within a parent element using `flexbox`.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "9b17338858339d7bb228e85fc7f8609b4728c9ba2107a636c486779c9c696c0c"
}
},
{
"id": "focus-within",
"type": "snippetListing",
"title": "Focus Within",
"attributes": {
"text": "Changes the appearance of a form if any of its children are focused.\n\n",
"tags": [
"visual",
"interactivity"
]
},
"meta": {
"hash": "6fd9c086b06248408f3934b3d21b513dc751ab023defea1841b03a5a9503fff3"
}
},
{
"id": "fullscreen",
"type": "snippetListing",
"title": "Fullscreen",
"attributes": {
"text": "The :fullscreen CSS pseudo-class represents an element that's displayed when the browser is in fullscreen mode.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "bc28c8d11259e58cb448d898b3ed31e8fc5b22e9840eee14c392368685755787"
}
},
{
"id": "ghost-trick",
"type": "snippetListing",
"title": "Ghost trick",
"attributes": {
"text": "Vertically centers an element in another.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "1e9448a7a3fdfda03eb9a43715bd508ea0ce84eaebedf147043fba2f586dc8dc"
}
},
{
"id": "gradient-text",
"type": "snippetListing",
"title": "Gradient text",
"attributes": {
"text": "Gives text a gradient color.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "974db536cfe1022d46c3a3fbec5f599a961de986a694c21fa9f493c880263f0d"
}
},
{
"id": "grid-centering",
"type": "snippetListing",
"title": "Grid centering",
"attributes": {
"text": "Horizontally and vertically centers a child element within a parent element using `grid`.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "6435b7dc7a403884583c6ed2062dce4e2a43d144578c5d4f6b3ab0882ca959f4"
}
},
{
"id": "hairline-border",
"type": "snippetListing",
"title": "Hairline border",
"attributes": {
"text": "Gives an element a border equal to 1 native device pixel in width, which can look\nvery sharp and crisp.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "89a7003fb239612b9ce94ebfaff95bc6bf88fec6990ab6256fff7b2ddfa6d42f"
}
},
{
"id": "height-transition",
"type": "snippetListing",
"title": "Height transition",
"attributes": {
"text": "Transitions an element's height from `0` to `auto` when its height is unknown.\n\n",
"tags": [
"animation"
]
},
"meta": {
"hash": "737b2ca54126cbcb200496d2c61a12ab5e43b9f09a084cfc8cc4f7afa242ad43"
}
},
{
"id": "hover-shadow-box-animation",
"type": "snippetListing",
"title": "Hover shadow box animation",
"attributes": {
"text": "Creates a shadow box around the text when it is hovered.\n\n",
"tags": [
"animation"
]
},
"meta": {
"hash": "b0e6bab9cb552d038d24121cfff46c630e6feeb073b3af6f055e9418c511e63b"
}
},
{
"id": "hover-underline-animation",
"type": "snippetListing",
"title": "Hover underline animation",
"attributes": {
"text": "Creates an animated underline effect when the text is hovered over.\n\n<small>**Credit:** https://flatuicolors.com/</small>\n\n",
"tags": [
"animation"
]
},
"meta": {
"hash": "9a97ba2c7f2f28ff9047373a3046d95eb7a9ff03de42d23568d669d61f30c6f1"
}
},
{
"id": "last-item-with-remaining-available-height",
"type": "snippetListing",
"title": "Last item with remaining available height",
"attributes": {
"text": "Take advantage of available viewport space by giving the last element the remaining available space in current viewport, even when resizing the window.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "2f925cc190a9744532de97bb4add65e53cc0b2f3833760f4e7263f5df17cfad5"
}
},
{
"id": "mouse-cursor-gradient-tracking",
"type": "snippetListing",
"title": "Mouse cursor gradient tracking",
"attributes": {
"text": "A hover effect where the gradient follows the mouse cursor.\n\n<small class=\"snippet__credit\">**Credit:** [Tobias Reich](https://codepen.io/electerious/pen/MQrRxX)</small>\n\n",
"tags": [
"visual",
"interactivity"
]
},
"meta": {
"hash": "95356deaaa912ba2c168ee418678ad99d1e000163c7b95f725364ba3cbbb5b85"
}
},
{
"id": "not-selector",
"type": "snippetListing",
"title": ":not selector",
"attributes": {
"text": "The `:not` psuedo selector is useful for styling a group of elements, while leaving the last (or specified) element unstyled.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "129748a7f6e0ee74a87e4ff4c62df53c40359c57047586c887fad9fc76872c04"
}
},
{
"id": "offscreen",
"type": "snippetListing",
"title": "Offscreen",
"attributes": {
"text": "A bulletproof way to completely hide an element visually and positionally in the DOM while still allowing it to be accessed by JavaScript and readable by screen readers. This method is very useful for accessibility ([ADA](https://adata.org/learn-about-ada)) development when more context is needed for visually-impaired users. As an alternative to `display: none` which is not readable by screen readers or `visibility: hidden` which takes up physical space in the DOM.\n\n",
"tags": [
"layout",
"visual"
]
},
"meta": {
"hash": "233e33b59ef7be00766dd0034ab54c6e788af637d761e71efb5c552153a9d163"
}
},
{
"id": "overflow-scroll-gradient",
"type": "snippetListing",
"title": "Overflow scroll gradient",
"attributes": {
"text": "Adds a fading gradient to an overflowing element to better indicate there is more content to be scrolled.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "938536c0407ce1d5edcf443ec9a51bdb22815662175ffdd372f5a7bc1446c865"
}
},
{
"id": "popout-menu",
"type": "snippetListing",
"title": "Popout menu",
"attributes": {
"text": "Reveals an interactive popout menu on hover and focus.\n\n",
"tags": [
"interactivity"
]
},
"meta": {
"hash": "c4ac484b5e94d0c326d1ac122ba9d9f98b71cd3ab3cce1cd3077fbd6e1afe4ee"
}
},
{
"id": "pretty-text-underline",
"type": "snippetListing",
"title": "Pretty text underline",
"attributes": {
"text": "A nicer alternative to `text-decoration: underline` or `<u></u>` where descenders do not clip the underline.\nNatively implemented as `text-decoration-skip-ink: auto` but it has less control over the underline.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "f91299fbd8d5233de42e09ef7c381a1cce23a83288f9e619f153af22a1275fd2"
}
},
{
"id": "reset-all-styles",
"type": "snippetListing",
"title": "Reset all styles",
"attributes": {
"text": "Resets all styles to default values with one property. This will not affect `direction` and `unicode-bidi` properties.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "1e52c4cc2c03669576b53d4be44357e6fea843cffd671419c881b31c927c9170"
}
},
{
"id": "shape-separator",
"type": "snippetListing",
"title": "Shape separator",
"attributes": {
"text": "Uses an SVG shape to separate two different blocks to create more a interesting visual appearance compared to standard horizontal separation.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "75e712c07e184d8dbf34818ba245f5b1a4273dfb491a21262b88042ef9e42d6c"
}
},
{
"id": "sibling-fade",
"type": "snippetListing",
"title": "Sibling fade",
"attributes": {
"text": "Fades out the siblings of a hovered item.\n\n",
"tags": [
"interactivity"
]
},
"meta": {
"hash": "c4b3ad85a5137635283abe843a9f180027bd751c40be9ca465b0b3e3f52b9fe9"
}
},
{
"id": "system-font-stack",
"type": "snippetListing",
"title": "System font stack",
"attributes": {
"text": "Uses the native font of the operating system to get close to a native app feel.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "23cfcc3319fd473b39269b2745abb7f52752a970307fc561159275208d04a554"
}
},
{
"id": "toggle-switch",
"type": "snippetListing",
"title": "Toggle switch",
"attributes": {
"text": "Creates a toggle switch with CSS only.\n\n",
"tags": [
"visual",
"interactivity"
]
},
"meta": {
"hash": "e29182514bd83550705267a43d21eec8886ed011c6259f2b3efec9862541f90e"
}
},
{
"id": "transform-centering",
"type": "snippetListing",
"title": "Transform centering",
"attributes": {
"text": "Vertically and horizontally centers a child element within its parent element using `position: absolute` and `transform: translate()` (as an alternative to `flexbox` or `display: table`). Similar to `flexbox`, this method does not require you to know the height or width of your parent or child so it is ideal for responsive applications.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "377d480a141a8890f793ef28212d7ed9d60c9d6831286bcea703ab43daca73ce"
}
},
{
"id": "triangle",
"type": "snippetListing",
"title": "Triangle",
"attributes": {
"text": "Creates a triangle shape with pure CSS.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "08382966ae74825502676c0bcdb77426abbf6202d813f5dfd6679d864fc1292e"
}
},
{
"id": "truncate-text-multiline",
"type": "snippetListing",
"title": "Truncate text multiline",
"attributes": {
"text": "If the text is longer than one line, it will be truncated for `n` lines and end with an gradient fade.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "ab94193bfb305844badfe15bda3594e75c40ac9660c11c06efd750119a916f8e"
}
},
{
"id": "truncate-text",
"type": "snippetListing",
"title": "Truncate text",
"attributes": {
"text": "If the text is longer than one line, it will be truncated and end with an ellipsis `…`.\n\n",
"tags": [
"layout"
]
},
"meta": {
"hash": "0fbe2c0df9663735aed522286556ac0383756ab0a1a5f673bb81dcb42f89d4d1"
}
},
{
"id": "zebra-striped-list",
"type": "snippetListing",
"title": "Zebra striped list",
"attributes": {
"text": "Creates a striped list with alternating background colors, which is useful for differentiating siblings that have content spread across a wide row.\n\n",
"tags": [
"visual"
]
},
"meta": {
"hash": "43bc0cd7776468f3b74791017349ef278921c8ded7ba0bd7788d2b01bdb68c7a"
}
}
],
"meta": {
"specification": "http://jsonapi.org/format/",
"type": "snippetListingArray"
}
}

1210
snippet_data/snippets.json Normal file

File diff suppressed because it is too large Load Diff

32
snippet_template.md Normal file
View File

@ -0,0 +1,32 @@
---
title: Snippet Name
tags: other,intermediate
---
Explain briefly what the snippet does.
```html
<div class="my-snippet"></div>
```
```css
.my-snippet {
background-color: #fff;
border: 1px solid #000;
border-radius: 4px;
}
```
```js
console.log("This is optional, if your snippet doesn't require JavaScript, be sure to delete this block!")
```
#### Explanation
- Explain briefly how the snippet works.
- Use bullet points for your snippet's explanation.
- Try to explain everything briefly but clearly.
#### Browser support
- https://www.caniuse.com/#feat=border-radius

View File

@ -1,9 +1,10 @@
### Bouncing loader
---
title: Bouncing loader
tags: animation
---
Creates a bouncing loader animation.
#### HTML
```html
<div class="bouncing-loader">
<div></div>
@ -12,8 +13,6 @@ Creates a bouncing loader animation.
</div>
```
#### CSS
```css
@keyframes bouncing-loader {
to {
@ -41,30 +40,21 @@ Creates a bouncing loader animation.
}
```
#### Demo
#### Explanation
Note: `1rem` is usually `16px`.
1. `@keyframes` defines an animation that has two states, where the element changes `opacity` and is translated up on the 2D plane using `transform: translate3d()`. Using a single axis translation on `transform: translate3d()` improves the performance of the animation.
2. `.bouncing-loader` is the parent container of the bouncing circles and uses `display: flex`
and `justify-content: center` to position them in the center.
2. `.bouncing-loader` is the parent container of the bouncing circles and uses `display: flex` and `justify-content: center` to position them in the center.
3. `.bouncing-loader > div`, targets the three child `div`s of the parent to be styled. The `div`s are given a width and height of `1rem`, using `border-radius: 50%` to turn them from squares to circles.
4. `margin: 3rem 0.2rem` specifies that each circle has a top/bottom margin of `3rem` and left/right margin
of `0.2rem` so that they do not directly touch each other, giving them some breathing room.
4. `margin: 3rem 0.2rem` specifies that each circle has a top/bottom margin of `3rem` and left/right margin of `0.2rem` so that they do not directly touch each other, giving them some breathing room.
5. `animation` is a shorthand property for the various animation properties: `animation-name`, `animation-duration`, `animation-iteration-count`, `animation-direction` are used.
6. `nth-child(n)` targets the element which is the nth child of its parent.
7. `animation-delay` is used on the second and third `div` respectively, so that each element does not start the animation at the same time.
#### Browser support
- https://caniuse.com/#feat=css-animation
<!-- tags: animation -->

View File

@ -1,16 +1,15 @@
### Box-sizing reset
---
title: Box-sizing reset
tags: layout
---
Resets the box-model so that `width`s and `height`s are not affected by their `border`s or `padding`.
#### HTML
```html
<div class="box">border-box</div>
<div class="box content-box">content-box</div>
```
#### CSS
```css
html {
box-sizing: border-box;
@ -34,8 +33,6 @@ html {
}
```
#### Demo
#### Explanation
1. `box-sizing: border-box` makes the addition of `padding` or `border`s not affect an element's `width` or `height`.
@ -45,4 +42,5 @@ html {
- https://caniuse.com/#feat=css3-boxsizing
<!-- tags: layout -->

View File

@ -1,15 +1,14 @@
### Button border animation
---
title: Button border animation
tags: animation
---
Creates a border animation on hover.
#### HTML
```html
<div class="button-border"><button class="button">Submit</button></div>
```
#### CSS
```css
.button {
background-color: #c47135;
@ -48,13 +47,8 @@ Creates a border animation on hover.
}
```
#### Demo
#### Explanation
Use the `:before` and `:after` pseduo-elements as borders that animate on hover.
- Use the `:before` and `:after` pseduo-elements as borders that animate on hover.
#### Browser support
<!-- tags: animation -->
<!-- date: 2018-10-30 -->

View File

@ -1,15 +1,14 @@
### Calc()
---
title: Calc()
tags: other
---
The function calc() allows to define CSS values with the use of mathematical expressions, the value adopted for the property is the result of a mathematical expression.
#### HTML
```html
<div class="box-example"></div>
```
#### CSS
```css
.box-example {
height: 280px;
@ -18,27 +17,6 @@ The function calc() allows to define CSS values with the use of mathematical exp
}
```
#### Demo
If you want to align a background-image from right and bottom wasn't possible with just straight length values.
So now it's possible using calc():
<div class="snippet-demo">
<div class="snippet-demo__calc">Background-image in the right/bottom</div>
</div>
<style>
.snippet-demo__calc {
height: 280px;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
background: #222 url('https://image.ibb.co/fUL9nS/wolf.png') no-repeat;
background-position: calc(100% - 20px) calc(100% - 40px);
}
</style>
#### Explanation
1. It allows addition, subtraction, multiplication and division.
@ -50,4 +28,5 @@ So now it's possible using calc():
- https://caniuse.com/#feat=calc
<!-- tags: other -->

View File

@ -1,15 +1,14 @@
### Circle
---
title: Circle
tags: visual
---
Creates a circle shape with pure CSS.
#### HTML
```html
<div class="circle"></div>
```
#### CSS
```css
.circle {
border-radius: 50%;
@ -19,17 +18,14 @@ Creates a circle shape with pure CSS.
}
```
#### Demo
#### Explanation
`border-radius: 50%` curves the borders of an element to create a circle.
Since a circle has the same radius at any given point, the `width` and `height` must be the same. Differing
values will create an ellipse.
- `border-radius: 50%` curves the borders of an element to create a circle.
- Since a circle has the same radius at any given point, the `width` and `height` must be the same. Differing values will create an ellipse.
#### Browser support
- https://caniuse.com/#feat=border-radius
<!-- tags: visual -->

View File

@ -1,11 +1,12 @@
### Clearfix
---
title: Clearfix
tags: layout
---
Ensures that an element self-clears its children.
###### Note: This is only useful if you are still using float to build layouts. Please consider using a modern approach with flexbox layout or grid layout.
#### HTML
```html
<div class="clearfix">
<div class="floated">float a</div>
@ -14,8 +15,6 @@ Ensures that an element self-clears its children.
</div>
```
#### CSS
```css
.clearfix::after {
content: '';
@ -28,17 +27,15 @@ Ensures that an element self-clears its children.
}
```
#### Demo
#### Explanation
1. `.clearfix::after` defines a pseudo-element.
2. `content: ''` allows the pseudo-element to affect layout.
3. `clear: both` indicates that the left, right or both sides of the element cannot be adjacent
to earlier floated elements within the same block formatting context.
3. `clear: both` indicates that the left, right or both sides of the element cannot be adjacent to earlier floated elements within the same block formatting context.
#### Browser support
<span class="snippet__support-note">⚠️ For this snippet to work properly you need to ensure that there are no non-floating children in the container and that there are no tall floats before the clearfixed container but in the same formatting context (e.g. floated columns).</span>
<!-- tags: layout -->

View File

@ -1,16 +1,15 @@
### Constant width to height ratio
---
title: Constant width to height ratio
tags: layout
---
Given an element of variable width, it will ensure its height remains proportionate in a responsive fashion
(i.e., its width to height ratio remains constant).
#### HTML
```html
<div class="constant-width-to-height-ratio"></div>
```
#### CSS
```css
.constant-width-to-height-ratio {
background: #333;
@ -28,16 +27,12 @@ Given an element of variable width, it will ensure its height remains proportion
}
```
#### Demo
#### Explanation
`padding-top` on the `::before` pseudo-element causes the height of the element to equal a percentage of
its width. `100%` therefore means the element's height will always be `100%` of the width, creating a responsive
square.
This method also allows content to be placed inside the element normally.
- `padding-top` on the `::before` pseudo-element causes the height of the element to equal a percentage of its width. `100%` therefore means the element's height will always be `100%` of the width, creating a responsive square.
- This method also allows content to be placed inside the element normally.
#### Browser support
<!-- tags: layout -->

View File

@ -1,9 +1,10 @@
### Counter
---
title: Counter
tags: visual, other
---
Counters are, in essence, variables maintained by CSS whose values may be incremented by CSS rules to track how many times they're used.
#### HTML
```html
<ul>
<li>List item</li>
@ -19,8 +20,6 @@ Counters are, in essence, variables maintained by CSS whose values may be increm
</ul>
```
#### CSS
```css
ul {
counter-reset: counter;
@ -32,24 +31,19 @@ li::before {
}
```
#### Demo
#### Explanation
You can create a ordered list using any type of HTML.
- You can create a ordered list using any type of HTML.
1. `counter-reset` Initializes a counter, the value is the name of the counter. By default, the counter starts at 0. This property can also be used to change its value to any specific number.
2. `counter-increment` Used in element that will be countable. Once `counter-reset` initialized, a counter's value can be increased or decreased.
3. `counter(name, style)` Displays the value of a section counter. Generally used in a `content` property. This function can receive two parameters, the first as the name of the counter and the second one can be `decimal` or `upper-roman` (`decimal` by default).
4. `counters(counter, string, style)` Displays the value of a section counter. Generally used in a `content` property. This function can receive three parameters, the first as the name of the counter, the second one you can include a string which comes after the counter and the third one can be `decimal` or `upper-roman` (`decimal` by default).
5. A CSS counter can be especially useful for making outlined lists, because a new instance of the counter is automatically created in child elements. Using the `counters()` function, separating text can be inserted between different levels of nested counters.
#### Browser support
- https://caniuse.com/#feat=css-counters
<!-- tags: visual, other -->

View File

@ -1,9 +1,10 @@
### Custom scrollbar
---
title: Custom scrollbar
tags: visual
---
Customizes the scrollbar style for the document and elements with scrollable overflow, on WebKit platforms.
#### HTML
```html
<div class="custom-scrollbar">
<p>
@ -15,8 +16,6 @@ Customizes the scrollbar style for the document and elements with scrollable ove
</div>
```
#### CSS
```css
.custom-scrollbar {
height: 70px;
@ -40,8 +39,6 @@ Customizes the scrollbar style for the document and elements with scrollable ove
}
```
#### Demo
#### Explanation
1. `::-webkit-scrollbar` targets the whole scrollbar element.
@ -56,4 +53,5 @@ There are many other pseudo-elements that you can use to style scrollbars. For m
- https://caniuse.com/#feat=css-scrollbar
<!-- tags: visual -->

View File

@ -1,15 +1,14 @@
### Custom text selection
---
title: Custom text selection
tags: visual
---
Changes the styling of text selection.
#### HTML
```html
<p class="custom-text-selection">Select some of this text.</p>
```
#### CSS
```css
::selection {
background: aquamarine;
@ -21,11 +20,9 @@ Changes the styling of text selection.
}
```
#### Demo
#### Explanation
`::selection` defines a pseudo selector on an element to style text within it when selected. Note that if you don't combine any other selector your style will be applied at document root level, to any selectable element.
- `::selection` defines a pseudo selector on an element to style text within it when selected. Note that if you don't combine any other selector your style will be applied at document root level, to any selectable element.
#### Browser support
@ -34,4 +31,5 @@ in any specification.</span>
- https://caniuse.com/#feat=css-selection
<!-- tags: visual -->

View File

@ -1,15 +1,14 @@
### Custom variables
---
title: Custom variables
tags: other
---
CSS variables that contain specific values to be reused throughout a document.
#### HTML
```html
<p class="custom-variables">CSS is awesome!</p>
```
#### CSS
```css
:root {
/* Place variables within here to use the variables globally. */
@ -27,18 +26,15 @@ CSS variables that contain specific values to be reused throughout a document.
}
```
#### Demo
#### Explanation
The variables are defined globally within the `:root` CSS pseudo-class which matches the root element of a tree representing the document. Variables can also be scoped to a selector if defined within the block.
Declare a variable with `--variable-name:`.
Reuse variables throughout the document using the `var(--variable-name)` function.
- The variables are defined globally within the `:root` CSS pseudo-class which matches the root element of a tree representing the document. Variables can also be scoped to a selector if defined within the block.
- Declare a variable with `--variable-name:`.
- Reuse variables throughout the document using the `var(--variable-name)` function.
#### Browser support
- https://caniuse.com/#feat=css-variables
<!-- tags: other -->

View File

@ -1,27 +1,24 @@
### Disable selection
---
title: Disable selection
tags: interactivity
---
Makes the content unselectable.
#### HTML
```html
<p>You can select me.</p>
<p class="unselectable">You can't select me!</p>
```
#### CSS
```css
.unselectable {
user-select: none;
}
```
#### Demo
#### Explanation
`user-select: none` specifies that the text cannot be selected.
- `user-select: none` specifies that the text cannot be selected.
#### Browser support
@ -31,4 +28,5 @@ Makes the content unselectable.
- https://caniuse.com/#feat=user-select-none
<!-- tags: interactivity -->

View File

@ -1,17 +1,16 @@
### Display table centering
---
title: Display table centering
tags: layout
---
Vertically and horizontally centers a child element within its parent element using `display: table` (as an alternative to `flexbox`).
#### HTML
```html
<div class="container">
<div class="center"><span>Centered content</span></div>
</div>
```
#### CSS
```css
.container {
border: 1px solid #333;
@ -32,8 +31,6 @@ Vertically and horizontally centers a child element within its parent element us
}
```
#### Demo
#### Explanation
1. `display: table` on '.center' allows the element to behave like a `<table>` HTML element.
@ -42,10 +39,11 @@ Vertically and horizontally centers a child element within its parent element us
4. `text-align: center` on '.center > span' centers the child element horizontally.
5. `vertical-align: middle` on '.center > span' centers the child element vertically.
The outer parent ('.container' in this case) must have a fixed height and width.
- The outer parent ('.container' in this case) must have a fixed height and width.
#### Browser support
- https://caniuse.com/#search=display%3A%20table
<!-- tags: layout -->

View File

@ -1,15 +1,14 @@
### Donut spinner
---
title: Donut spinner
tags: animation
---
Creates a donut spinner that can be used to indicate the loading of content.
#### HTML
```html
<div class="donut"></div>
```
#### CSS
```css
@keyframes donut-spin {
0% {
@ -30,12 +29,9 @@ Creates a donut spinner that can be used to indicate the loading of content.
}
```
#### Demo
#### Explanation
Use a semi-transparent `border` for the whole element, except one side that will
serve as the loading indicator for the donut. Use `animation` to rotate the element.
- Use a semi-transparent `border` for the whole element, except one side that will serve as the loading indicator for the donut. Use `animation` to rotate the element.
#### Browser support
@ -44,4 +40,5 @@ serve as the loading indicator for the donut. Use `animation` to rotate the elem
- https://caniuse.com/#feat=css-animation
- https://caniuse.com/#feat=transforms2d
<!-- tags: animation -->

View File

@ -1,15 +1,14 @@
### Dynamic shadow
---
title: Dynamic shadow
tags: visual
---
Creates a shadow similar to `box-shadow` but based on the colors of the element itself.
#### HTML
```html
<div class="dynamic-shadow"></div>
```
#### CSS
```css
.dynamic-shadow {
position: relative;
@ -31,8 +30,6 @@ Creates a shadow similar to `box-shadow` but based on the colors of the element
}
```
#### Demo
#### Explanation
1. `position: relative` on the element establishes a Cartesian positioning context for psuedo-elements.
@ -52,4 +49,5 @@ Creates a shadow similar to `box-shadow` but based on the colors of the element
- https://caniuse.com/#feat=css-filters
<!-- tags: visual -->

View File

@ -1,16 +1,15 @@
### Easing variables
---
title: Easing variables
tags: animation
---
Variables that can be reused for `transition-timing-function` properties, more
powerful than the built-in `ease`, `ease-in`, `ease-out` and `ease-in-out`.
#### HTML
```html
<div class="easing-variables">Hover</div>
```
#### CSS
```css
:root {
/* Place variables in here to use globally */
@ -53,14 +52,14 @@ powerful than the built-in `ease`, `ease-in`, `ease-out` and `ease-in-out`.
}
```
#### Demo
#### Explanation
The variables are defined globally within the `:root` CSS pseudo-class which matches the root element of a tree representing the document. In HTML, `:root` represents the `<html>` element and is identical to the selector `html`, except that its specificity is higher.
- The variables are defined globally within the `:root` CSS pseudo-class which matches the root element of a tree representing the document.
- In HTML, `:root` represents the `<html>` element and is identical to the selector `html`, except that its specificity is higher.
#### Browser support
- https://caniuse.com/#feat=css-variables
<!-- tags: animation -->

View File

@ -1,15 +1,14 @@
### Etched text
---
title: Etched text
tags: visual
---
Creates an effect where text appears to be "etched" or engraved into the background.
#### HTML
```html
<p class="etched-text">I appear etched into the background.</p>
```
#### CSS
```css
.etched-text {
text-shadow: 0 2px white;
@ -19,20 +18,15 @@ Creates an effect where text appears to be "etched" or engraved into the backgro
}
```
#### Demo
#### Explanation
`text-shadow: 0 2px white` creates a white shadow offset `0px` horizontally and `2px` vertically
from the origin position.
The background must be darker than the shadow for the effect to work.
The text color should be slightly faded to make it look like it's engraved/carved out
of the background.
- `text-shadow: 0 2px white` creates a white shadow offset `0px` horizontally and `2px` vertically from the origin position.
- The background must be darker than the shadow for the effect to work.
- The text color should be slightly faded to make it look like it's engraved/carved out of the background.
#### Browser support
- https://caniuse.com/#feat=css-textshadow
<!-- tags: visual -->

View File

@ -1,9 +1,10 @@
### Evenly distributed children
---
title: Evenly distributed children
tags: layout
---
Evenly distributes child elements within a parent element.
#### HTML
```html
<div class="evenly-distributed-children">
<p>Item1</p>
@ -12,8 +13,6 @@ Evenly distributes child elements within a parent element.
</div>
```
#### CSS
```css
.evenly-distributed-children {
display: flex;
@ -21,14 +20,12 @@ Evenly distributes child elements within a parent element.
}
```
#### Demo
#### Explanation
1. `display: flex` enables flexbox.
2. `justify-content: space-between` evenly distributes child elements horizontally. The first item is positioned at the left edge, while the last item is positioned at the right edge.
Alternatively, use `justify-content: space-around` to distribute the children with space around them, rather than between them.
- Alternatively, use `justify-content: space-around` to distribute the children with space around them, rather than between them.
#### Browser support
@ -36,4 +33,5 @@ Alternatively, use `justify-content: space-around` to distribute the children wi
- https://caniuse.com/#feat=flexbox
<!-- tags: layout -->

View File

@ -1,16 +1,15 @@
### Fit image in container
---
title: Fit image in container
tags: layout, visual
---
Changes the fit and position of an image within its container while preserving its aspect ratio. Previously only possible using a background image and the `background-size` property.
#### HTML
```html
<img class="image image-contain" src="https://picsum.photos/600/200" />
<img class="image image-cover" src="https://picsum.photos/600/200" />
```
#### CSS
```css
.image {
background: #34495e;
@ -30,8 +29,6 @@ Changes the fit and position of an image within its container while preserving i
}
```
#### Demo
#### Explanation
- `object-fit: contain` fits the entire image within the container while preserving its aspect ratio.
@ -41,6 +38,3 @@ Changes the fit and position of an image within its container while preserving i
#### Browser support
- https://caniuse.com/#feat=object-fit
<!-- tags: layout, visual -->
<!-- date: 2018-10-31 -->

View File

@ -1,15 +1,14 @@
### Flexbox centering
---
title: Flexbox centering
tags: layout
---
Horizontally and vertically centers a child element within a parent element using `flexbox`.
#### HTML
```html
<div class="flexbox-centering"><div class="child">Centered content.</div></div>
```
#### CSS
```css
.flexbox-centering {
display: flex;
@ -19,8 +18,6 @@ Horizontally and vertically centers a child element within a parent element usin
}
```
#### Demo
#### Explanation
1. `display: flex` enables flexbox.
@ -33,4 +30,5 @@ Horizontally and vertically centers a child element within a parent element usin
- https://caniuse.com/#feat=flexbox
<!-- tags: layout -->

View File

@ -1,9 +1,10 @@
### Focus Within
---
title: Focus Within
tags: visual, interactivity
---
Changes the appearance of a form if any of its children are focused.
#### HTML
```html
<div class="focus-within">
<form>
@ -13,8 +14,6 @@ Changes the appearance of a form if any of its children are focused.
</div>
```
#### CSS
```css
form {
border: 3px solid #2d98da;
@ -28,13 +27,11 @@ form:focus-within {
}
```
#### Demo
<!-- Leave this blank, the build script will generate the demo for you. -->
#### Explanation
The psuedo class `:focus-within` applies styles to a parent element if any child element gets focused. For example, an `input` element inside a `form` element.
- The psuedo class `:focus-within` applies styles to a parent element if any child element gets focused. For example, an `input` element inside a `form` element.
#### Browser support
@ -45,4 +42,5 @@ If no link is provided, it defaults to 99+%. -->
- https://caniuse.com/#feat=css-focus-within
<!-- tags: visual, interactivity -->

View File

@ -1,9 +1,10 @@
### Fullscreen
---
title: Fullscreen
tags: visual
---
The :fullscreen CSS pseudo-class represents an element that's displayed when the browser is in fullscreen mode.
#### HTML
```html
<div class="container">
<p><em>Click the button below to enter the element into fullscreen mode. </em></p>
@ -15,8 +16,6 @@ The :fullscreen CSS pseudo-class represents an element that's displayed when the
</div>
```
#### CSS
```css
.container {
margin: 40px auto;
@ -47,8 +46,6 @@ The :fullscreen CSS pseudo-class represents an element that's displayed when the
}
```
#### Demo
#### Explanation
1. `fullscreen` CSS pseudo-class selector is used to select and style an element that is being displayed in fullscreen mode.
@ -58,4 +55,5 @@ The :fullscreen CSS pseudo-class represents an element that's displayed when the
- https://developer.mozilla.org/en-US/docs/Web/CSS/:fullscreen
- https://caniuse.com/#feat=fullscreen
<!-- tags: visual -->

View File

@ -1,17 +1,16 @@
### Ghost trick
---
title: Ghost trick
tags: layout
---
Vertically centers an element in another.
#### HTML
```html
<div class="ghost-trick">
<div class="ghosting"><p>Vertically centered without changing the position property.</p></div>
</div>
```
#### CSS
```css
.ghosting {
height: 300px;
@ -31,14 +30,13 @@ p {
}
```
#### Demo
#### Explanation
Use the style of a `:before` pseudo-element to vertically align inline elements without changing their `position` property.
- Use the style of a `:before` pseudo-element to vertically align inline elements without changing their `position` property.
#### Browser support
- https://caniuse.com/#feat=inline-block
<!-- tags: layout -->

View File

@ -1,15 +1,14 @@
### Gradient text
---
title: Gradient text
tags: visual
---
Gives text a gradient color.
#### HTML
```html
<p class="gradient-text">Gradient text</p>
```
#### CSS
```css
.gradient-text {
background: -webkit-linear-gradient(pink, red);
@ -18,14 +17,11 @@ Gives text a gradient color.
}
```
#### Demo
#### Explanation
1. `background: -webkit-linear-gradient(...)` gives the text element a gradient background.
2. `webkit-text-fill-color: transparent` fills the text with a transparent color.
3. `webkit-background-clip: text` clips the background with the text, filling the text with
the gradient background as the color.
3. `webkit-background-clip: text` clips the background with the text, filling the text with the gradient background as the color.
#### Browser support
@ -33,4 +29,5 @@ Gives text a gradient color.
- https://caniuse.com/#feat=text-stroke
<!-- tags: visual -->

View File

@ -1,15 +1,14 @@
### Grid centering
---
title: Grid centering
tags: layout
---
Horizontally and vertically centers a child element within a parent element using `grid`.
#### HTML
```html
<div class="grid-centering"><div class="child">Centered content.</div></div>
```
#### CSS
```css
.grid-centering {
display: grid;
@ -19,8 +18,6 @@ Horizontally and vertically centers a child element within a parent element usin
}
```
#### Demo
#### Explanation
1. `display: grid` enables grid.
@ -31,4 +28,5 @@ Horizontally and vertically centers a child element within a parent element usin
- https://caniuse.com/#feat=css-grid
<!-- tags: layout -->

View File

@ -1,16 +1,15 @@
### Hairline border
---
title: Hairline border
tags: visual
---
Gives an element a border equal to 1 native device pixel in width, which can look
very sharp and crisp.
#### HTML
```html
<div class="hairline-border">text</div>
```
#### CSS
```css
.hairline-border {
box-shadow: 0 0 0 1px;
@ -35,13 +34,10 @@ very sharp and crisp.
}
```
#### Demo
#### Explanation
1. `box-shadow`, when only using spread, adds a pseudo-border which can use subpixels\*.
2. Use `@media (min-resolution: ...)` to check the device pixel ratio (`1dppx` equals 96 DPI),
setting the spread of the `box-shadow` equal to `1 / dppx`.
2. Use `@media (min-resolution: ...)` to check the device pixel ratio (`1dppx` equals 96 DPI), setting the spread of the `box-shadow` equal to `1 / dppx`.
#### Browser Support
@ -54,4 +50,5 @@ very sharp and crisp.
\*Chrome does not support subpixel values on `border`. Safari does not support subpixel values on `box-shadow`. Firefox supports subpixel values on both.
<!-- tags: visual -->

View File

@ -1,9 +1,10 @@
### Height transition
---
title: Height transition
tags: animation
---
Transitions an element's height from `0` to `auto` when its height is unknown.
#### HTML
```html
<div class="trigger">
Hover me to see a height transition.
@ -11,8 +12,6 @@ Transitions an element's height from `0` to `auto` when its height is unknown.
</div>
```
#### CSS
```css
.el {
transition: max-height 0.5s;
@ -25,30 +24,20 @@ Transitions an element's height from `0` to `auto` when its height is unknown.
}
```
#### JavaScript
```js
var el = document.querySelector('.el')
var height = el.scrollHeight
el.style.setProperty('--max-height', height + 'px')
```
#### Demo
#### Explanation
##### CSS
1. `transition: max-height: 0.5s cubic-bezier(...)` specifies that changes to `max-height` should be transitioned over 0.5 seconds, using an `ease-out-quint` timing function.
2. `overflow: hidden` prevents the contents of the hidden element from overflowing its container.
3. `max-height: 0` specifies that the element has no height initially.
4. `.target:hover > .el` specifies that when the parent is hovered over, target a child `.el` within
it and use the `--max-height` variable which was defined by JavaScript.
##### JavaScript
1. `el.scrollHeight` is the height of the element including overflow, which will change dynamically
based on the content of the element.
4. `.target:hover > .el` specifies that when the parent is hovered over, target a child `.el` within it and use the `--max-height` variable which was defined by JavaScript.
---
1. `el.scrollHeight` is the height of the element including overflow, which will change dynamically based on the content of the element.
2. `el.style.setProperty(...)` sets the `--max-height` CSS variable which is used to specify the `max-height` of the element the target is hovered over, allowing it to transition smoothly from 0 to auto.
#### Browser Support
@ -62,4 +51,5 @@ el.style.setProperty('--max-height', height + 'px')
- https://caniuse.com/#feat=css-variables
- https://caniuse.com/#feat=css-transitions
<!-- tags: animation -->

View File

@ -1,15 +1,14 @@
### Hover shadow box animation
---
title: Hover shadow box animation
tags: animation
---
Creates a shadow box around the text when it is hovered.
#### HTML
```html
<p class="hover-shadow-box-animation">Box it!</p>
```
#### CSS
```css
.hover-shadow-box-animation {
display: inline-block;
@ -28,8 +27,6 @@ Creates a shadow box around the text when it is hovered.
}
```
#### Demo
#### Explanation
1. `display: inline-block` to set width and length for `p` element thus making it an `inline-block`.
@ -45,4 +42,5 @@ Creates a shadow box around the text when it is hovered.
- https://caniuse.com/#feat=transforms3d
- https://caniuse.com/#feat=css-transitions
<!-- tags: animation -->

View File

@ -1,17 +1,16 @@
### Hover underline animation
---
title: Hover underline animation
tags: animation
---
Creates an animated underline effect when the text is hovered over.
<small>**Credit:** https://flatuicolors.com/</small>
#### HTML
```html
<p class="hover-underline-animation">Hover this text to see the effect!</p>
```
#### CSS
```css
.hover-underline-animation {
display: inline-block;
@ -36,28 +35,23 @@ Creates an animated underline effect when the text is hovered over.
}
```
#### Demo
#### Explanation
1. `display: inline-block` makes the block `p` an `inline-block` to prevent the underline from
spanning the entire parent width rather than just the content (text).
1. `display: inline-block` makes the block `p` an `inline-block` to prevent the underline from spanning the entire parent width rather than just the content (text).
2. `position: relative` on the element establishes a Cartesian positioning context for pseudo-elements.
3. `::after` defines a pseudo-element.
4. `position: absolute` takes the pseudo element out of the flow of the document and positions it in relation to the parent.
5. `width: 100%` ensures the pseudo-element spans the entire width of the text block.
6. `transform: scaleX(0)` initially scales the pseudo element to 0 so it has no width and is not visible.
7. `bottom: 0` and `left: 0` position it to the bottom left of the block.
8. `transition: transform 0.25s ease-out` means changes to `transform` will be transitioned over 0.25 seconds
with an `ease-out` timing function.
8. `transition: transform 0.25s ease-out` means changes to `transform` will be transitioned over 0.25 seconds with an `ease-out` timing function.
9. `transform-origin: bottom right` means the transform anchor point is positioned at the bottom right of the block.
10. `:hover::after` then uses `scaleX(1)` to transition the width to 100%, then changes the `transform-origin`
to `bottom left` so that the anchor point is reversed, allowing it transition out in the other direction when
hovered off.
10. `:hover::after` then uses `scaleX(1)` to transition the width to 100%, then changes the `transform-origin` to `bottom left` so that the anchor point is reversed, allowing it transition out in the other direction when hovered off.
#### Browser support
- https://caniuse.com/#feat=transforms2d
- https://caniuse.com/#feat=css-transitions
<!-- tags: animation -->

View File

@ -1,9 +1,10 @@
### Last item with remaining available height
---
title: Last item with remaining available height
tags: layout
---
Take advantage of available viewport space by giving the last element the remaining available space in current viewport, even when resizing the window.
#### HTML
```html
<div class="container">
<div>Div 1</div>
@ -12,8 +13,6 @@ Take advantage of available viewport space by giving the last element the remain
</div>
```
#### CSS
```css
html,
body {
@ -33,8 +32,6 @@ body {
}
```
#### Demo
#### Explanation
1. `height: 100%` set the height of container as viewport height.
@ -42,13 +39,10 @@ body {
3. `flex-direction: column` set the direction of flex items' order from top to down.
4. `flex-grow: 1` the flexbox will apply remaining available space of container to last child element.
The parent must have a viewport height. `flex-grow: 1` could be applied to the first or second element, which will have all available space.
- The parent must have a viewport height. `flex-grow: 1` could be applied to the first or second element, which will have all available space.
#### Browser support
<span class="snippet__support-note">⚠️ Needs prefixes for full support.</span>
- https://caniuse.com/#feat=flexbox
<!-- tags: layout -->
<!-- date: 2018-09-30 -->

View File

@ -1,17 +1,16 @@
### Mouse cursor gradient tracking
---
title: Mouse cursor gradient tracking
tags: visual, interactivity
---
A hover effect where the gradient follows the mouse cursor.
<small class="snippet__credit">**Credit:** [Tobias Reich](https://codepen.io/electerious/pen/MQrRxX)</small>
#### HTML
```html
<button class="mouse-cursor-gradient-tracking"><span>Hover me</span></button>
```
#### CSS
```css
.mouse-cursor-gradient-tracking {
position: relative;
@ -47,8 +46,6 @@ A hover effect where the gradient follows the mouse cursor.
}
```
#### JavaScript
```js
var btn = document.querySelector('.mouse-cursor-gradient-tracking')
btn.onmousemove = function(e) {
@ -59,17 +56,17 @@ btn.onmousemove = function(e) {
}
```
#### Demo
#### Explanation
_TODO_
1. `--x` and `--y` are used to track the position of the mouse on the button.
2. `--size` is used to keep modify of the gradient's dimensions.
3. `background: radial-gradient(circle closest-side, pink, transparent);` creates the gradient at the correct postion.
#### Browser support
<div class="snippet__requires-javascript">Requires JavaScript</div>
<span class="snippet__support-note">⚠️ Requires JavaScript.</span>
- https://caniuse.com/#feat=css-variables
<!-- tags: visual, interactivity -->

View File

@ -1,9 +1,10 @@
### :not selector
---
title: :not selector
tags: visual
---
The `:not` psuedo selector is useful for styling a group of elements, while leaving the last (or specified) element unstyled.
#### HTML
```html
<ul class="css-not-selector-shortcut">
<li>One</li>
@ -13,8 +14,6 @@ The `:not` psuedo selector is useful for styling a group of elements, while leav
</ul>
```
#### CSS
```css
.css-not-selector-shortcut {
display: flex;
@ -35,15 +34,13 @@ li:not(:last-child) {
}
```
#### Demo
#### Explanation
`li:not(:last-child)` specifies that the styles should apply to all `li` elements except
the `:last-child`.
- `li:not(:last-child)` specifies that the styles should apply to all `li` elements except the `:last-child`.
#### Browser support
- https://caniuse.com/#feat=css-sel3
<!-- tags: visual -->

View File

@ -1,17 +1,16 @@
### Offscreen
---
title: Offscreen
tags: layout, visual
---
A bulletproof way to completely hide an element visually and positionally in the DOM while still allowing it to be accessed by JavaScript and readable by screen readers. This method is very useful for accessibility ([ADA](https://adata.org/learn-about-ada)) development when more context is needed for visually-impaired users. As an alternative to `display: none` which is not readable by screen readers or `visibility: hidden` which takes up physical space in the DOM.
#### HTML
```html
<a class="button" href="http://pantswebsite.com">
Learn More <span class="offscreen"> about pants</span>
</a>
```
#### CSS
```css
.offscreen {
border: 0;
@ -25,8 +24,6 @@ A bulletproof way to completely hide an element visually and positionally in the
}
```
#### Demo
#### Explanation
1. Remove all borders.
@ -43,4 +40,5 @@ A bulletproof way to completely hide an element visually and positionally in the
- https://caniuse.com/#search=clip
<!-- tags: layout, visual -->

View File

@ -1,9 +1,10 @@
### Overflow scroll gradient
---
title: Overflow scroll gradient
tags: visual
---
Adds a fading gradient to an overflowing element to better indicate there is more content to be scrolled.
#### HTML
```html
<div class="overflow-scroll-gradient">
<div class="overflow-scroll-gradient__scroller">
@ -19,8 +20,6 @@ Adds a fading gradient to an overflowing element to better indicate there is mor
</div>
```
#### CSS
```css
.overflow-scroll-gradient {
position: relative;
@ -47,17 +46,13 @@ Adds a fading gradient to an overflowing element to better indicate there is mor
}
```
#### Demo
#### Explanation
1. `position: relative` on the parent establishes a Cartesian positioning context for pseudo-elements.
2. `::after` defines a pseudo element.
3. `background-image: linear-gradient(...)` adds a linear gradient that fades from transparent to white
(top to bottom).
3. `background-image: linear-gradient(...)` adds a linear gradient that fades from transparent to white (top to bottom).
4. `position: absolute` takes the pseudo element out of the flow of the document and positions it in relation to the parent.
5. `width: 240px` matches the size of the scrolling element (which is a child of the parent that has
the pseudo element).
5. `width: 240px` matches the size of the scrolling element (which is a child of the parent that has the pseudo element).
6. `height: 25px` is the height of the fading gradient pseudo-element, which should be kept relatively small.
7. `bottom: 0` positions the pseudo-element at the bottom of the parent.
8. `pointer-events: none` specifies that the pseudo-element cannot be a target of mouse events, allowing text behind it to still be selectable/interactive.
@ -66,4 +61,5 @@ Adds a fading gradient to an overflowing element to better indicate there is mor
- https://caniuse.com/#feat=css-gradients
<!-- tags: visual -->

View File

@ -1,15 +1,14 @@
### Popout menu
---
title: Popout menu
tags: interactivity
---
Reveals an interactive popout menu on hover and focus.
#### HTML
```html
<div class="reference" tabindex="0"><div class="popout-menu">Popout menu</div></div>
```
#### CSS
```css
.reference {
position: relative;
@ -32,8 +31,6 @@ Reveals an interactive popout menu on hover and focus.
}
```
#### Demo
#### Explanation
1. `position: relative` on the reference parent establishes a Cartesian positioning context for its child.
@ -46,4 +43,5 @@ Reveals an interactive popout menu on hover and focus.
#### Browser support
<!-- tags: interactivity -->

View File

@ -1,16 +1,15 @@
### Pretty text underline
---
title: Pretty text underline
tags: visual
---
A nicer alternative to `text-decoration: underline` or `<u></u>` where descenders do not clip the underline.
Natively implemented as `text-decoration-skip-ink: auto` but it has less control over the underline.
#### HTML
```html
<p class="pretty-text-underline">Pretty text underline without clipping descending letters.</p>
```
#### CSS
```css
.pretty-text-underline {
display: inline;
@ -30,25 +29,17 @@ Natively implemented as `text-decoration-skip-ink: auto` but it has less control
}
```
#### Demo
#### Explanation
1. `text-shadow` uses 4 values with offsets that cover a 4x4 px area to ensure the underline
has a "thick" shadow that covers the line where descenders clip it. Use a color
that matches the background. For a larger font, use a larger `px` size. Additional values
can create an even thicker shadow, and subpixel values can also be used.
2. `background-image: linear-gradient(...)` creates a 90deg gradient using the
text color (`currentColor`).
3. The `background-*` properties size the gradient as 100% of the width of the block and 1px
in height at the bottom and disables repetition, which creates a 1px underline beneath
the text.
4. The `::selection` pseudo selector rule ensures the text shadow does not interfere with text
selection.
1. `text-shadow` uses 4 values with offsets that cover a 4x4 px area to ensure the underline has a "thick" shadow that covers the line where descenders clip it. Use a color that matches the background. For a larger font, use a larger `px` size. Additional values can create an even thicker shadow, and subpixel values can also be used.
2. `background-image: linear-gradient(...)` creates a 90deg gradient using the text color (`currentColor`).
3. The `background-*` properties size the gradient as 100% of the width of the block and 1px in height at the bottom and disables repetition, which creates a 1px underline beneath the text.
4. The `::selection` pseudo selector rule ensures the text shadow does not interfere with text selection.
#### Browser support
- https://caniuse.com/#feat=css-textshadow
- https://caniuse.com/#feat=css-gradients
<!-- tags: visual -->

View File

@ -1,9 +1,10 @@
### Reset all styles
---
title: Reset all styles
tags: visual
---
Resets all styles to default values with one property. This will not affect `direction` and `unicode-bidi` properties.
#### HTML
```html
<div class="reset-all-styles">
<h5>Title</h5>
@ -15,19 +16,15 @@ Resets all styles to default values with one property. This will not affect `dir
</div>
```
#### CSS
```css
.reset-all-styles {
all: initial;
}
```
#### Demo
#### Explanation
The `all` property allows you to reset all styles (inherited or not) to default values.
- The `all` property allows you to reset all styles (inherited or not) to default values.
#### Browser support
@ -35,4 +32,5 @@ The `all` property allows you to reset all styles (inherited or not) to default
- https://caniuse.com/#feat=css-all
<!-- tags: visual -->

View File

@ -1,15 +1,14 @@
### Shape separator
---
title: Shape separator
tags: visual
---
Uses an SVG shape to separate two different blocks to create more a interesting visual appearance compared to standard horizontal separation.
#### HTML
```html
<div class="shape-separator"></div>
```
#### CSS
```css
.shape-separator {
position: relative;
@ -26,8 +25,6 @@ Uses an SVG shape to separate two different blocks to create more a interesting
}
```
#### Demo
#### Explanation
1. `position: relative` on the element establishes a Cartesian positioning context for pseudo elements.
@ -42,4 +39,5 @@ Uses an SVG shape to separate two different blocks to create more a interesting
- https://caniuse.com/#feat=svg
<!-- tags: visual -->

View File

@ -1,9 +1,10 @@
### Sibling fade
---
title: Sibling fade
tags: interactivity
---
Fades out the siblings of a hovered item.
#### HTML
```html
<div class="sibling-fade">
<span>Item 1</span> <span>Item 2</span> <span>Item 3</span> <span>Item 4</span>
@ -11,8 +12,6 @@ Fades out the siblings of a hovered item.
</div>
```
#### CSS
```css
span {
padding: 0 1rem;
@ -24,17 +23,15 @@ span {
}
```
#### Demo
#### Explanation
1. `transition: opacity 0.2s` specifies that changes to opacity will be transitioned over 0.2 seconds.
2. `.sibling-fade:hover span:not(:hover)` specifies that when the parent is hovered, select any `span` children
that are not currently being hovered and change their opacity to `0.5`.
2. `.sibling-fade:hover span:not(:hover)` specifies that when the parent is hovered, select any `span` children that are not currently being hovered and change their opacity to `0.5`.
#### Browser support
- https://caniuse.com/#feat=css-sel3
- https://caniuse.com/#feat=css-transitions
<!-- tags: interactivity -->

View File

@ -1,15 +1,14 @@
### System font stack
---
title: System font stack
tags: visual
---
Uses the native font of the operating system to get close to a native app feel.
#### HTML
```html
<p class="system-font-stack">This text uses the system font.</p>
```
#### CSS
```css
.system-font-stack {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu,
@ -17,12 +16,9 @@ Uses the native font of the operating system to get close to a native app feel.
}
```
#### Demo
#### Explanation
The browser looks for each successive font, preferring the first one if possible, and
falls back to the next if it cannot find the font (on the system or defined in CSS).
- The browser looks for each successive font, preferring the first one if possible, and falls back to the next if it cannot find the font (on the system or defined in CSS).
1. `-apple-system` is San Francisco, used on iOS and macOS (not Chrome however)
2. `BlinkMacSystemFont` is San Francisco, used on macOS Chrome
@ -37,4 +33,5 @@ falls back to the next if it cannot find the font (on the system or defined in C
#### Browser support
<!-- tags: visual -->

View File

@ -1,15 +1,14 @@
### Toggle switch
---
title: Toggle switch
tags: visual, interactivity
---
Creates a toggle switch with CSS only.
#### HTML
```html
<input type="checkbox" id="toggle" class="offscreen" /> <label for="toggle" class="switch"></label>
```
#### CSS
```css
.switch {
position: relative;
@ -47,11 +46,9 @@ input[type='checkbox']:checked + .switch {
}
```
#### Demo
#### Explanation
This effect is styling only the `<label>` element to look like a toggle switch, and hiding the actual `<input>` checkbox by positioning it offscreen. When clicking the label associated with the `<input>` element, it sets the `<input>` checkbox into the `:checked` state.
- This effect is styling only the `<label>` element to look like a toggle switch, and hiding the actual `<input>` checkbox by positioning it offscreen. When clicking the label associated with the `<input>` element, it sets the `<input>` checkbox into the `:checked` state.
1. The `for` attribute associates the `<label>` with the appropriate `<input>` checkbox element by its `id`.
2. `.switch::after` defines a pseudo-element for the `<label>` to create the circular knob.
@ -66,6 +63,3 @@ This effect is styling only the `<label>` element to look like a toggle switch,
<span class="snippet__support-note">⚠️ Requires prefixes for full support.</span>
- https://caniuse.com/#feat=transforms2d
<!-- tags: visual, interactivity -->
<!-- date: 2018-10-03 -->

View File

@ -1,15 +1,14 @@
### Transform centering
---
title: Transform centering
tags: layout
---
Vertically and horizontally centers a child element within its parent element using `position: absolute` and `transform: translate()` (as an alternative to `flexbox` or `display: table`). Similar to `flexbox`, this method does not require you to know the height or width of your parent or child so it is ideal for responsive applications.
#### HTML
```html
<div class="parent"><div class="child">Centered content</div></div>
```
#### CSS
```css
.parent {
border: 1px solid #333;
@ -27,15 +26,13 @@ Vertically and horizontally centers a child element within its parent element us
}
```
#### Demo
#### Explanation
1. `position: absolute` on the child element allows it to be positioned based on its containing block.
2. `left: 50%` and `top: 50%` offsets the child 50% from the left and top edge of its containing block.
3. `transform: translate(-50%, -50%)` allows the height and width of the child element to be negated so that it is vertically and horizontally centered.
Note: Fixed height and width on parent element is for the demo only.
- Note: that the fixed height and width on parent element is for the demo only.
#### Browser support
@ -43,4 +40,5 @@ Note: Fixed height and width on parent element is for the demo only.
- https://caniuse.com/#feat=transforms2d
<!-- tags: layout -->

View File

@ -1,15 +1,14 @@
### Triangle
---
title: Triangle
tags: visual
---
Creates a triangle shape with pure CSS.
#### HTML
```html
<div class="triangle"></div>
```
#### CSS
```css
.triangle {
width: 0;
@ -20,18 +19,13 @@ Creates a triangle shape with pure CSS.
}
```
#### Demo
#### Explanation
[View this link for a detailed explanation.](https://stackoverflow.com/q/7073484)
The color of the border is the color of the triangle. The side the triangle tip points
corresponds to the opposite `border-*` property. For example, a color on `border-top`
means the arrow points downward.
Experiment with the `px` values to change the proportion of the triangle.
- [View this link for a detailed explanation.](https://stackoverflow.com/q/7073484)
- The color of the border is the color of the triangle. The side the triangle tip points corresponds to the opposite `border-*` property. For example, a color on `border-top` means the arrow points downward.
- Experiment with the `px` values to change the proportion of the triangle.
#### Browser support
<!-- tags: visual -->

Some files were not shown because too many files have changed in this diff Show More