<div class="demo">
<div>
<a href="https://github.com/maliMirkec/Classily.js" class="button-switch js-classily" data-target="this" data-class="button-switch--off" data-prevent="default">
<span>Off</span>
<span>On</span>
</a>
</div>
</div>
$mq-mobile: 320px;
$mq-desktop: 960px;
@function strip-unit($value) {
@return $value / ($value * 0 + 1);
}
@mixin css-locks($properties, $min-vw, $max-vw, $min-value, $max-value) {
@each $property in $properties {
#{$property}: $min-value;
}
@media screen and (min-width: $min-vw) {
@each $property in $properties {
#{$property}: calc(#{$min-value} + #{strip-unit($max-value - $min-value)} * (100vw - #{$min-vw}) / #{strip-unit($max-vw - $min-vw)});
}
}
@media screen and (min-width: $max-vw) {
@each $property in $properties {
#{$property}: $max-value;
}
}
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
html {
font-family: -apple-system, BlinkMacSystemFont,
"Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans",
"Droid Sans", "Helvetica Neue", sans-serif;
@include css-locks(font-size, $mq-mobile, $mq-desktop, 15px, 20px);
}
body {
min-height: 100vh;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
}
.demo {
flex: 1 1 auto;
display: flex;
flex-direction: column;
align-items: center;
padding: 2rem;
.button-switch {
display: inline-flex;
color: darken(#fff, 5%);
background-color: transparentize(#fff, .8);
background-clip: padding-box;
font-size: .875rem;
font-weight: 600;
letter-spacing: .06em;
border: 0.25rem solid transparent;
border-radius: 0.5rem;
margin-bottom: 0.25rem;
position: relative;
text-shadow: 0 1px 0 Black;
text-transform: uppercase;
text-decoration: none;
text-align: center;
box-shadow: 0 1px 3px -1px Black;
outline: 0;
cursor: pointer;
transition: all 0.15s ease-out;
&:before {
content: '';
background-color: Blue;
background-image: linear-gradient(to bottom right, transparentize(#ff6347, .45), transparentize(#ff6347, .9));
border-radius: 0.5rem;
position: absolute;
top: -0.25rem;
right: -0.25rem;
bottom: -0.25rem;
left: -0.25rem;
z-index: -1;
transition: background-color 0.15s linear;
}
&:after {
content: '';
background-color: transparentize(#fff, .5);
border-radius: 0.25rem;
box-shadow: 0 1px 2px -1px Gray, 0 1px 2px -1px White inset;
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: calc(50%);
transform: translateX(100%);
transition: transform 0.05s ease-out;
}
&.button-switch--off:after {
transform: translateX(0);
}
span {
padding: 1rem;
}
&:hover {
color: White;
&:before {
background-color: Purple;
}
}
&:active {
box-shadow: none;
}
}
}
View Compiled
(function (root, factory) {
const pluginName = 'Classily'
if (typeof define === 'function' && define.amd) {
define([], factory(pluginName))
} else if (typeof exports === 'object') {
module.exports = factory(pluginName)
} else {
window[pluginName] = factory(pluginName)
}
}(this, (pluginName) => {
const defaults = {
selector: '.js-classily'
}
/**
* Merge defaults with user options
* @param {Object} defaults Default settings
* @param {Object} options User options
*/
const extend = function (target, options) {
const extended = {}
Object.keys(defaults).forEach((prop) => {
if (Object.prototype.hasOwnProperty.call(defaults, prop)) {
extended[prop] = defaults[prop]
}
})
Object.keys(options).forEach((prop) => {
if (Object.prototype.hasOwnProperty.call(options, prop)) {
extended[prop] = options[prop]
}
})
return extended
}
/**
@private
* Find target elements and toggle classes
* @param {Object} cur Current element (that users clicks on)
* @param {String} sel Selectors for finding target elements
* @param {String} cl Classes ti toggle on target elements
*/
const toggleFunction = (cur, sel, cl) => {
let $tar = Array.prototype.slice.call(document.querySelectorAll(sel))
if (sel.indexOf('this') !== -1) {
$tar.push(cur)
}
if ($tar) {
const cls = cl.split(' ');
for (let i = 0; i < $tar.length; i += 1) {
for (let j = 0; j < cls.length; j += 1) {
$tar[i].classList.toggle(cls[j].trim())
}
}
}
}
/**
@private
* Get config parameters from data attributes and pass them to toggle function
* @param {Object} event Event object (click)
*/
const toggleEvent = (event) => {
if (event.currentTarget.getAttribute('data-prevent') === 'default') {
event.preventDefault()
}
const selectors = event.currentTarget.getAttribute('data-target').split(',')
const classes = event.currentTarget.getAttribute('data-class').split(',')
if (selectors.length === classes.length) {
selectors.forEach((currentSelector, j) => {
toggleFunction(event.currentTarget, currentSelector.trim(), classes[j].trim())
})
} else {
const targetSelector = selectors.map(selectorItem => selectorItem.trim()).join(',')
const targetClass = classes.map(classItem => classItem.trim()).join(' ')
toggleFunction(event.currentTarget, targetSelector, targetClass)
}
}
/**
* Plugin Object
* @param {Object} options User options
* @constructor
*/
function Classily (options) {
this.options = extend(defaults, options)
this.init()
}
/**
* Classily prototype
* @public
* @constructor
*/
Classily.prototype = {
init () {
// Find all matching DOM elements
this.selectors = document.querySelectorAll(this.options.selector)
for (let i = 0; i < this.selectors.length; i += 1) {
const selector = this.selectors[i]
// Attach click event on matching DOM element and call toggle event
selector.addEventListener('click', toggleEvent)
}
},
destroy () {
// Find all matching DOM elements
this.selectors = document.querySelectorAll(this.options.selector)
for (let i = 0; i < this.selectors.length; i += 1) {
const selector = this.selectors[i]
// Dettach click event on matching DOM element
selector.removeEventListener('click', toggleEvent)
}
}
}
return Classily
}))
new Classily({
selector: ".js-classily"
});
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.