HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by Skypack, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ES6 import
usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<div id="grid" data-columns>
<div class="con">Item #1 海明叫決慢要屋景者爸氣此師是身原相中支老企笑如沒?切口平講傳產那具;雙中情真滿氣;得影治兒,小又起日你制,說教時林備公色那基思。講行環!我應運解地個心學健。</div>
<div class="con">Item #2 頭幾雙:了知的標節,了異我決要的我說見來場推習命個聽像作,我社舉心親時了觀民我,如進減大園我,那書者希型工方送我修感決是來。要學積行專,電世國班知片日導持,經力什,一民書智、濟力乎不學除所同像音氣。色考達全面而我企生得因究內間童道就制現,對需作大行覺過明分減界心想力期我此……然是玩賽立有息候藝城我毛於考海步是過方著滿後族照家大費起裝被化造成的家他時。果裝讀道情上表著教。那定天指很共放,角國學……這種布處個至交體預不制新我地己汽人孩定一不我流媽,容案學職以。</div>
<div class="con">Item #3 加的們著入放有;專才手力線情灣蘭親了吃們長子車高士說力發腦先一消,要可說影他與林別念靜水兩推創題來也幾!的心出該死題立演地像選的舞,自際海,們化院成!以動報問備此中電基治,老生則是獎風後上經上太改路,口就東常了行業通不為印給色角價學,以紀理快,為神然布謝始史究它不示舉一社聽盡發;一子港友神言決視加生正背;開收當;成推例作病兩那,們女上母不己孩人有排不,代氣兒。產頭們政不樣本電大打超義。親觀反、五要回司情候,術標正線的母讀花屋化;童現臺雄展火母象不性示濟,會充性易性後然安成合有、這像答來。作看女出待要與品能代在老。美及種!部黨天灣人實他部臺格放想張英給要實那表話臺、軍北一水是是美們麼色文三教後?</div>
<div class="con">Item #4 界對到了華育活家地之共:法點起身,說包身高多最是。</div>
<div class="con">Item #5 孩定一不我流媽,容案學職以。
成底星機國裡去那因接氣主班今向來立的灣制天任,女效教那石:各課易極,能綠在城市則部特老包機……重黑我,原於可環?國人代兩作發往,專運業著,中多氣南設快前老工下?員邊空的道會?</div>
<div class="con">Item #6</div>
</div>
.con {
padding: 1rem;
background: #eee;
border: solid 1px #777;
box-sizing: border-box;
}
@media screen and (max-width: 480px){
#grid[data-columns]::before {
content: '1 .column.size-1of1';
}
}
@media screen and (min-width: 481px) and (max-width: 768px) {
#grid[data-columns]::before {
content: '2 .column.size-1of2';
}
}
@media screen and (min-width: 769px) {
#grid[data-columns]::before {
content: '3 .column.size-1of3';
}
}
/* Again, you’re free to use and define the classes: */
.column { float: left; }
.size-1of1 { width: 100%; }
.size-1of2 { width: 50%; }
.size-1of3 { width: 33.333%; }
/* .con {
width: 100%;
} */
/*!
* Salvattore 1.0.9 by @rnmp and @ppold
* https://github.com/rnmp/salvattore
*/
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.salvattore = factory();
}
}(this, function() {
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
if (!window.matchMedia) {
window.matchMedia = function() {
"use strict";
// For browsers that support matchMedium api such as IE 9 and webkit
var styleMedia = (window.styleMedia || window.media);
// For those that don't support matchMedium
if (!styleMedia) {
var style = document.createElement('style'),
script = document.getElementsByTagName('script')[0],
info = null;
style.type = 'text/css';
style.id = 'matchmediajs-test';
script.parentNode.insertBefore(style, script);
// 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle;
styleMedia = {
matchMedium: function(media) {
var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }';
// 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
if (style.styleSheet) {
style.styleSheet.cssText = text;
} else {
style.textContent = text;
}
// Test if media query is true or false
return info.width === '1px';
}
};
}
return function(media) {
return {
matches: styleMedia.matchMedium(media || 'all'),
media: media || 'all'
};
};
}();
}
/*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */
(function(){
"use strict";
// Bail out for browsers that have addListener support
if (window.matchMedia && window.matchMedia('all').addListener) {
return false;
}
var localMatchMedia = window.matchMedia,
hasMediaQueries = localMatchMedia('only all').matches,
isListening = false,
timeoutID = 0, // setTimeout for debouncing 'handleChange'
queries = [], // Contains each 'mql' and associated 'listeners' if 'addListener' is used
handleChange = function(evt) {
// Debounce
clearTimeout(timeoutID);
timeoutID = setTimeout(function() {
for (var i = 0, il = queries.length; i < il; i++) {
var mql = queries[i].mql,
listeners = queries[i].listeners || [],
matches = localMatchMedia(mql.media).matches;
// Update mql.matches value and call listeners
// Fire listeners only if transitioning to or from matched state
if (matches !== mql.matches) {
mql.matches = matches;
for (var j = 0, jl = listeners.length; j < jl; j++) {
listeners[j].call(window, mql);
}
}
}
}, 30);
};
window.matchMedia = function(media) {
var mql = localMatchMedia(media),
listeners = [],
index = 0;
mql.addListener = function(listener) {
// Changes would not occur to css media type so return now (Affects IE <= 8)
if (!hasMediaQueries) {
return;
}
// Set up 'resize' listener for browsers that support CSS3 media queries (Not for IE <= 8)
// There should only ever be 1 resize listener running for performance
if (!isListening) {
isListening = true;
window.addEventListener('resize', handleChange, true);
}
// Push object only if it has not been pushed already
if (index === 0) {
index = queries.push({
mql : mql,
listeners : listeners
});
}
listeners.push(listener);
};
mql.removeListener = function(listener) {
for (var i = 0, il = listeners.length; i < il; i++){
if (listeners[i] === listener){
listeners.splice(i, 1);
}
}
};
return mql;
};
}());
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function() {
"use strict";
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] ||
window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
if (typeof window.CustomEvent !== "function") {
(function() {
"use strict";
function CustomEvent(event, params) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
})();
}
/* jshint laxcomma: true */
var salvattore = (function (global, document, undefined) {
"use strict";
var self = {},
grids = [],
mediaRules = [],
mediaQueries = [],
add_to_dataset = function(element, key, value) {
// uses dataset function or a fallback for <ie10
if (element.dataset) {
element.dataset[key] = value;
} else {
element.setAttribute("data-" + key, value);
}
return;
};
self.obtainGridSettings = function obtainGridSettings(element) {
// returns the number of columns and the classes a column should have,
// from computing the style of the ::before pseudo-element of the grid.
var computedStyle = global.getComputedStyle(element, ":before")
, content = computedStyle.getPropertyValue("content").slice(1, -1)
, matchResult = content.match(/^\s*(\d+)(?:\s?\.(.+))?\s*$/)
, numberOfColumns = 1
, columnClasses = []
;
if (matchResult) {
numberOfColumns = matchResult[1];
columnClasses = matchResult[2];
columnClasses = columnClasses? columnClasses.split(".") : ["column"];
} else {
matchResult = content.match(/^\s*\.(.+)\s+(\d+)\s*$/);
if (matchResult) {
columnClasses = matchResult[1];
numberOfColumns = matchResult[2];
if (numberOfColumns) {
numberOfColumns = numberOfColumns.split(".");
}
}
}
return {
numberOfColumns: numberOfColumns,
columnClasses: columnClasses
};
};
self.addColumns = function addColumns(grid, items) {
// from the settings obtained, it creates columns with
// the configured classes and adds to them a list of items.
var settings = self.obtainGridSettings(grid)
, numberOfColumns = settings.numberOfColumns
, columnClasses = settings.columnClasses
, columnsItems = new Array(+numberOfColumns)
, columnsFragment = document.createDocumentFragment()
, i = numberOfColumns
, selector
;
while (i-- !== 0) {
selector = "[data-columns] > *:nth-child(" + numberOfColumns + "n-" + i + ")";
columnsItems.push(items.querySelectorAll(selector));
}
columnsItems.forEach(function append_to_grid_fragment(rows) {
var column = document.createElement("div")
, rowsFragment = document.createDocumentFragment()
;
column.className = columnClasses.join(" ");
Array.prototype.forEach.call(rows, function append_to_column(row) {
rowsFragment.appendChild(row);
});
column.appendChild(rowsFragment);
columnsFragment.appendChild(column);
});
grid.appendChild(columnsFragment);
add_to_dataset(grid, 'columns', numberOfColumns);
};
self.removeColumns = function removeColumns(grid) {
// removes all the columns from a grid, and returns a list
// of items sorted by the ordering of columns.
var range = document.createRange();
range.selectNodeContents(grid);
var columns = Array.prototype.filter.call(range.extractContents().childNodes, function filter_elements(node) {
return node instanceof global.HTMLElement;
});
var numberOfColumns = columns.length
, numberOfRowsInFirstColumn = columns[0].childNodes.length
, sortedRows = new Array(numberOfRowsInFirstColumn * numberOfColumns)
;
Array.prototype.forEach.call(columns, function iterate_columns(column, columnIndex) {
Array.prototype.forEach.call(column.children, function iterate_rows(row, rowIndex) {
sortedRows[rowIndex * numberOfColumns + columnIndex] = row;
});
});
var container = document.createElement("div");
add_to_dataset(container, 'columns', 0);
sortedRows.filter(function filter_non_null(child) {
return !!child;
}).forEach(function append_row(child) {
container.appendChild(child);
});
return container;
};
self.recreateColumns = function recreateColumns(grid) {
// removes all the columns from the grid, and adds them again,
// it is used when the number of columns change.
global.requestAnimationFrame(function render_after_css_mediaQueryChange() {
self.addColumns(grid, self.removeColumns(grid));
var columnsChange = new CustomEvent("columnsChange");
grid.dispatchEvent(columnsChange);
});
};
self.mediaQueryChange = function mediaQueryChange(mql) {
// recreates the columns when a media query matches the current state
// of the browser.
if (mql.matches) {
Array.prototype.forEach.call(grids, self.recreateColumns);
}
};
self.getCSSRules = function getCSSRules(stylesheet) {
// returns a list of css rules from a stylesheet
var cssRules;
try {
cssRules = stylesheet.sheet.cssRules || stylesheet.sheet.rules;
} catch (e) {
return [];
}
return cssRules || [];
};
self.getStylesheets = function getStylesheets() {
// returns a list of all the styles in the document (that are accessible).
var inlineStyleBlocks = Array.prototype.slice.call(document.querySelectorAll("style"));
inlineStyleBlocks.forEach(function(stylesheet, idx) {
if (stylesheet.type !== 'text/css' && stylesheet.type !== '') {
inlineStyleBlocks.splice(idx, 1);
}
});
return Array.prototype.concat.call(
inlineStyleBlocks,
Array.prototype.slice.call(document.querySelectorAll("link[rel='stylesheet']"))
);
};
self.mediaRuleHasColumnsSelector = function mediaRuleHasColumnsSelector(rules) {
// checks if a media query css rule has in its contents a selector that
// styles the grid.
var i, rule;
try {
i = rules.length;
}
catch (e) {
i = 0;
}
while (i--) {
rule = rules[i];
if (rule.selectorText && rule.selectorText.match(/\[data-columns\](.*)::?before$/)) {
return true;
}
}
return false;
};
self.scanMediaQueries = function scanMediaQueries() {
// scans all the stylesheets for selectors that style grids,
// if the matchMedia API is supported.
var newMediaRules = [];
if (!global.matchMedia) {
return;
}
self.getStylesheets().forEach(function extract_rules(stylesheet) {
Array.prototype.forEach.call(self.getCSSRules(stylesheet), function filter_by_column_selector(rule) {
// rule.media throws an 'not implemented error' in ie9 for import rules occasionally
try {
if (rule.media && rule.cssRules && self.mediaRuleHasColumnsSelector(rule.cssRules)) {
newMediaRules.push(rule);
}
} catch (e) {}
});
});
// remove matchMedia listeners from the old rules
var oldRules = mediaRules.filter(function (el) {
return newMediaRules.indexOf(el) === -1;
});
mediaQueries.filter(function (el) {
return oldRules.indexOf(el.rule) !== -1;
}).forEach(function (el) {
el.mql.removeListener(self.mediaQueryChange);
});
mediaQueries = mediaQueries.filter(function (el) {
return oldRules.indexOf(el.rule) === -1;
});
// add matchMedia listeners to the new rules
newMediaRules.filter(function (el) {
return mediaRules.indexOf(el) == -1;
}).forEach(function (rule) {
var mql = global.matchMedia(rule.media.mediaText);
mql.addListener(self.mediaQueryChange);
mediaQueries.push({rule: rule, mql:mql});
});
// swap mediaRules with the new set
mediaRules.length = 0;
mediaRules = newMediaRules;
};
self.rescanMediaQueries = function rescanMediaQueries() {
self.scanMediaQueries();
Array.prototype.forEach.call(grids, self.recreateColumns);
};
self.nextElementColumnIndex = function nextElementColumnIndex(grid, fragments) {
// returns the index of the column where the given element must be added.
var children = grid.children
, m = children.length
, lowestRowCount = 0
, child
, currentRowCount
, i
, index = 0
;
for (i = 0; i < m; i++) {
child = children[i];
currentRowCount = child.children.length + (fragments[i].children || fragments[i].childNodes).length;
if(lowestRowCount === 0) {
lowestRowCount = currentRowCount;
}
if(currentRowCount < lowestRowCount) {
index = i;
lowestRowCount = currentRowCount;
}
}
return index;
};
self.createFragmentsList = function createFragmentsList(quantity) {
// returns a list of fragments
var fragments = new Array(quantity)
, i = 0
;
while (i !== quantity) {
fragments[i] = document.createDocumentFragment();
i++;
}
return fragments;
};
self.appendElements = function appendElements(grid, elements) {
// adds a list of elements to the end of a grid
var columns = grid.children
, numberOfColumns = columns.length
, fragments = self.createFragmentsList(numberOfColumns)
;
Array.prototype.forEach.call(elements, function append_to_next_fragment(element) {
var columnIndex = self.nextElementColumnIndex(grid, fragments);
fragments[columnIndex].appendChild(element);
});
Array.prototype.forEach.call(columns, function insert_column(column, index) {
column.appendChild(fragments[index]);
});
};
self.prependElements = function prependElements(grid, elements) {
// adds a list of elements to the start of a grid
var columns = grid.children
, numberOfColumns = columns.length
, fragments = self.createFragmentsList(numberOfColumns)
, columnIndex = numberOfColumns - 1
;
elements.forEach(function append_to_next_fragment(element) {
var fragment = fragments[columnIndex];
fragment.insertBefore(element, fragment.firstChild);
if (columnIndex === 0) {
columnIndex = numberOfColumns - 1;
} else {
columnIndex--;
}
});
Array.prototype.forEach.call(columns, function insert_column(column, index) {
column.insertBefore(fragments[index], column.firstChild);
});
// populates a fragment with n columns till the right
var fragment = document.createDocumentFragment()
, numberOfColumnsToExtract = elements.length % numberOfColumns
;
while (numberOfColumnsToExtract-- !== 0) {
fragment.appendChild(grid.lastChild);
}
// adds the fragment to the left
grid.insertBefore(fragment, grid.firstChild);
};
self.registerGrid = function registerGrid (grid) {
if (global.getComputedStyle(grid).display === "none") {
return;
}
// retrieve the list of items from the grid itself
var range = document.createRange();
range.selectNodeContents(grid);
var items = document.createElement("div");
items.appendChild(range.extractContents());
add_to_dataset(items, 'columns', 0);
self.addColumns(grid, items);
grids.push(grid);
};
self.init = function init() {
// adds required CSS rule to hide 'content' based
// configuration.
var css = document.createElement("style");
css.innerHTML = "[data-columns]::before{display:block;visibility:hidden;position:absolute;font-size:1px;}";
document.head.appendChild(css);
// scans all the grids in the document and generates
// columns from their configuration.
var gridElements = document.querySelectorAll("[data-columns]");
Array.prototype.forEach.call(gridElements, self.registerGrid);
self.scanMediaQueries();
};
self.init();
return {
appendElements: self.appendElements,
prependElements: self.prependElements,
registerGrid: self.registerGrid,
recreateColumns: self.recreateColumns,
rescanMediaQueries: self.rescanMediaQueries,
init: self.init,
// maintains backwards compatibility with underscore style method names
append_elements: self.appendElements,
prepend_elements: self.prependElements,
register_grid: self.registerGrid,
recreate_columns: self.recreateColumns,
rescan_media_queries: self.rescanMediaQueries
};
})(window, window.document);
return salvattore;
}));
Also see: Tab Triggers