Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

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.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              <div class="filter-controls">
	<label for="filter-grayscale">
    <span class="filter-name">
      grayscale
    </span>
    <input type="range" step=".1" min="0" max="1" value="1" id="filter-grayscale">
    <span class="filter-val">1</span>
  </label>
	<label for="filter-contrast">
    <span class="filter-name">contrast</span>
    <input type="range" step=".05" min="0" max="2" value="1.5" id="filter-contrast">
    <span class="filter-val">1.5</span>
  </label>
	<label for="filter-brightness">
    <span class="filter-name">
      brightness
    </span>
    <input type="range" step=".05" min="0" max="2" value=".95" id="filter-brightness">
    <span class="filter-val">.95</span>
  </label>
</div>
<label class="raw-img" for="raw-img"><input type="checkbox"  class="visually-hidden" id="raw-img">show original images</label>
<div class="images">
	<div class="fig" style="--hue: 350">
		<img src="https://drive.google.com/uc?export=view&id=1Uh7sPoEbaSRuodllgQnyLdIvdglLvy_h" alt="Lizzo">

		<label for="fig-1-hue">
    hue
    <input type="range" id="fig-1-hue" min="0" max="360" value="350">
       <span class="hue-val"> 
    350  
    </span>
  </label>
	</div>

	<div class="fig" style="--hue: 214">
		<img src="https://drive.google.com/uc?export=view&id=1X2RxDhWm6pn15admoG5RWo6z2XA088Xo" alt="Fiona Apple">
		<label for="fig-2-hue">
    hue
    <input type="range" id="fig-2-hue" min="0" max="360" value="214">
    <span class="hue-val"> 
    214
    </span>
  </label>
	</div>

	<div class="fig" style="--hue: 30">
		<img src="https://drive.google.com/uc?export=view&id=1ZhU-xJkEvAJhz8tak860uUAYq_-DTc4X" alt="St. Vincent">
		<label for="fig-3-hue">
     hue
    <input type="range" id="fig-3-hue" min="0" max="360" value="30">
         <span class="hue-val"> 
    30
    </span>
  </label>
	</div>
</div>
            
          
!
            
              :root {
	/*  used for the filter values on the image to make them look a bit uniform   */
	--grayscale: 1;
	--contrast: 1.6;
	--brightness: 0.95;

	/*  saturation and lightness on image's color; didn't include options for these to keep a more uniform look  */
	--saturation: 35%;
	--lightness: 60%;
}

.fig {
	/*  what gives the image its color (using mix-blend-mode on the image) */
	background-color: hsl(var(--hue), var(--saturation), var(--lightness));
	max-width: 20rem;
	max-height: 20rem;
}

img {
	filter: grayscale(var(--grayscale)) contrast(var(--contrast))
		brightness(var(--brightness));
	mix-blend-mode: multiply;

	display: block;
	object-fit: cover;
	width: 100%;
	height: 100%;
}

/* to show original images  */
.raw img {
	filter: none;
	mix-blend-mode: unset;
}

/* general layout / styles  */

::selection {
	background-color: #111;
	color: #fff;
}

::-moz-selection {
	background-color: #111;
	color: #fff;
}

body {
	margin: 0;
	display: flex;
	flex-direction: column;
	justify-content: center;
	min-height: 100vh;
	padding: 1.5rem;
}

.filter-controls {
	border-left: 0.5rem solid;
	border-image: linear-gradient(to bottom, #fff 10%, #111, #fff 90%);
	border-image-slice: 1;
	padding: 0.5rem;
}

/* to keep filter input ranges lined up */
.filter-name {
	/*  max chars in filter names  */
	width: 11ch;
}

/* keeps the input range from jumping around as values change */
[class*="-val"] {
	width: 3ch;
	text-align: right;
}

.images {
	display: grid;
	grid-gap: 1rem;
	grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
	grid-gap: 1rem;
	align-items: center;
	justify-items: center;
	padding: 1.5rem;
}

label {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-around;
	padding: 0.5rem;
	background-color: #fff;
	font-family: "Courier New", "Andale Mono", "Courier Next", courier, monospace;
}

.raw-img {
	margin: 1.5rem auto 0;
	justify-content: center;
	position: relative;
	cursor: pointer;
}

/* custom checkbox */
.raw-img::before {
	content: "";
	width: 1rem;
	height: 1rem;
	margin-right: 0.5rem;
	border: thin solid;
}

/* partially filled in checkbox when checked */
.raw .raw-img::before {
	background-image: linear-gradient(to bottom right, #111 50%, #fff 50%);
}

/* input range track */

::-webkit-slider-runnable-track {
	-webkit-appearance: none;
	-moz-appearance: none;
	appearance: none;
	position: relative;
	margin: auto;
	display: block;
	height: 0.35rem;
	border-radius: 2px;
	background-color: #111;
}

::-moz-range-track {
	-moz-appearance: none;
	appearance: none;
	position: relative;
	margin: auto;
	display: block;
	height: 0.35rem;
	border-radius: 2px;
	background-color: #111;
}

::-ms-track {
	-webkit-appearance: none;
	-moz-appearance: none;
	appearance: none;
	position: relative;
	margin: auto;
	display: block;
	height: 0.35rem;
	border-radius: 2px;
	background-color: #111;
}

/* range thumb */

::-webkit-slider-thumb {
	-webkit-appearance: none;
	cursor: pointer;
	margin-top: -0.25rem;
}

::-moz-range-thumb {
	cursor: pointer;
}

::-ms-thumb {
	cursor: pointer;
}

.visually-hidden {
	height: 1px !important;
	width: 1px !important;
	position: absolute !important;
	overflow: hidden !important;
	clip-path: inset(100%) !important;
	clip: rect(1px, 1px, 1px, 1px) !important;
	white-space: nowrap !important;
}

            
          
!
            
              function updateHue(e) {
	// value of the input range to use as the new hue
	const val = e.target.value;
	// parent element to get and set --hue prop
	const fig = e.target.closest(".fig");
	// hue value text output
	const text = fig.querySelector(".hue-val");

	changeProp(fig, "--hue", val);
	text.textContent = val;
}

function updateFilterVal(e) {
	const val = e.target.value;
	// get custom property name of input
	const prop = `--${e.target.id.replace(/filter-/, "")}`;
	const text = e.target.parentNode.querySelector(".filter-val");

	changeProp(document.documentElement, prop, val);
	text.textContent = val;
}

function changeProp(el, prop, val) {
	el.style.setProperty(prop, val);
	console.log(el, prop, val);
}

const hueInputs = [...document.querySelectorAll('[id^="fig-"]')];

const filterInputs = [...document.querySelectorAll('[id^="filter-"]')];

const rawOpt = document.getElementById("raw-img");

hueInputs.forEach(input => input.addEventListener("input", updateHue));

filterInputs.forEach(input => input.addEventListener("input", updateFilterVal));

rawOpt.addEventListener("input", () => document.body.classList.toggle("raw"));

            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.

Console