Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

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.

+ add another resource

JavaScript

Babel includes JSX processing.

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

Packages

Add Packages

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.

Behavior

Auto Save

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.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div class="pn-ProductNav_Wrapper">
<nav id="pnProductNav" class="pn-ProductNav">
    <div id="pnProductNavContents" class="pn-ProductNav_Contents">
        <a href="#" class="pn-ProductNav_Link" aria-selected="true">Chairs</a>
        <a href="#" class="pn-ProductNav_Link">Tables</a>
        <a href="#" class="pn-ProductNav_Link">Cookware</a>
        <a href="#" class="pn-ProductNav_Link">Beds</a>
        <a href="#" class="pn-ProductNav_Link">Desks</a>
        <a href="#" class="pn-ProductNav_Link">Flooring</a>
        <a href="#" class="pn-ProductNav_Link">Lighting</a>
        <a href="#" class="pn-ProductNav_Link">Mattresses</a>
        <a href="#" class="pn-ProductNav_Link">Solar Panels</a>
        <a href="#" class="pn-ProductNav_Link">Bookcases</a>
        <a href="#" class="pn-ProductNav_Link">Mirrors</a>
        <a href="#" class="pn-ProductNav_Link">Rugs</a>  
        <a href="#" class="pn-ProductNav_Link">Curtains &amp; Blinds</a>  
        <a href="#" class="pn-ProductNav_Link">Frames &amp; Pictures</a>  
        <a href="#" class="pn-ProductNav_Link">Wardrobes</a>  
        <a href="#" class="pn-ProductNav_Link">Storage</a>  
        <a href="#" class="pn-ProductNav_Link">Decoration</a>  
        <a href="#" class="pn-ProductNav_Link">Appliances</a>
		 <a href="#" class="pn-ProductNav_Link">Racks</a>
        <a href="#" class="pn-ProductNav_Link">Worktops</a>
	<span id="pnIndicator" class="pn-ProductNav_Indicator"></span>
    </div>
</nav>
	<button id="pnAdvancerLeft" class="pn-Advancer pn-Advancer_Left" type="button">
		<svg class="pn-Advancer_Icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 551 1024"><path d="M445.44 38.183L-2.53 512l447.97 473.817 85.857-81.173-409.6-433.23v81.172l409.6-433.23L445.44 38.18z"/></svg>
	</button>
	<button id="pnAdvancerRight" class="pn-Advancer pn-Advancer_Right" type="button">
		<svg class="pn-Advancer_Icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 551 1024"><path d="M105.56 985.817L553.53 512 105.56 38.183l-85.857 81.173 409.6 433.23v-81.172l-409.6 433.23 85.856 81.174z"/></svg>
	</button>
</div>
              
            
!

CSS

              
                * {
	box-sizing: inherit;
}

.pn-ProductNav_Wrapper {
	position: relative;
	padding: 0 11px;
	box-sizing: border-box;
}

.pn-ProductNav {
    /* Make this scrollable when needed */
    overflow-x: auto;
    /* We don't want vertical scrolling */
    overflow-y: hidden;
    /* For WebKit implementations, provide inertia scrolling */
    -webkit-overflow-scrolling: touch;
    /* We don't want internal inline elements to wrap */
    white-space: nowrap;
    /* If JS present, let's hide the default scrollbar */
    .js & {
        /* Make an auto-hiding scroller for the 3 people using a IE */
        -ms-overflow-style: -ms-autohiding-scrollbar;
        /* Remove the default scrollbar for WebKit implementations */
        &::-webkit-scrollbar {
            display: none;
        }
    }
	/* positioning context for advancers */
	position: relative;
	// Crush the whitespace here
	font-size: 0;
}

.pn-ProductNav_Contents {
	float: left;
	transition: transform .2s ease-in-out;
}

.pn-ProductNav_Contents-no-transition {
	transition: none;
}

.pn-ProductNav_Link {
	text-decoration: none;
	color: #888;
	// Reset the font size
	font-size: 1.2rem;
	font-family: -apple-system, sans-serif;
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	border: 1px solid transparent;
	padding: 0 11px;
	& + & {
		border-left-color: #eee;
	}
	&[aria-selected="true"] {
		color: #111;
	}
}

.pn-Advancer {
	/* Reset the button */
	appearance: none;
	background: transparent;
	padding: 0;
	border: 0;
	&:focus {
		outline: 0;
	}
	&:hover {
		cursor: pointer;
	}
	/* Now style it as needed */
	position: absolute;
	top: 0;
	bottom: 0;
	/* Set the buttons invisible by default */
	opacity: 0;
	transition: opacity .3s;
}

.pn-Advancer_Left {
	left: 0;
	[data-overflowing="both"] ~ &,
	[data-overflowing="left"] ~ & {
		opacity: 1;
	}
}

.pn-Advancer_Right {
	right: 0;
	[data-overflowing="both"]  ~ &,
	[data-overflowing="right"] ~ & {
		opacity: 1;
	}
}

.pn-Advancer_Icon {
	width: 20px;
	height: 44px;
	fill: #bbb;
}

.pn-ProductNav_Indicator {
	position: absolute;
	bottom: 0;
	left: 0;
	height: 4px;
	width: 100px;
	background-color: transparent;
	transform-origin: 0 0;
	transition: transform .2s ease-in-out, background-color .2s ease-in-out;
}
              
            
!

JS

              
                var SETTINGS = {
    navBarTravelling: false,
    navBarTravelDirection: "",
	 navBarTravelDistance: 150
}

var colours = {
    0: "#867100",
    1: "#7F4200",
    2: "#99813D",
    3: "#40FEFF",
    4: "#14CC99",
    5: "#00BAFF",
    6: "#0082B2",
    7: "#B25D7A",
    8: "#00FF17",
    9: "#006B49",
    10: "#00B27A",
    11: "#996B3D",
    12: "#CC7014",
    13: "#40FF8C",
    14: "#FF3400",
    15: "#ECBB5E",
    16: "#ECBB0C",
    17: "#B9D912",
    18: "#253A93",
    19: "#125FB9",
}

document.documentElement.classList.remove("no-js");
document.documentElement.classList.add("js");

// Out advancer buttons
var pnAdvancerLeft = document.getElementById("pnAdvancerLeft");
var pnAdvancerRight = document.getElementById("pnAdvancerRight");
// the indicator
var pnIndicator = document.getElementById("pnIndicator");

var pnProductNav = document.getElementById("pnProductNav");
var pnProductNavContents = document.getElementById("pnProductNavContents");

pnProductNav.setAttribute("data-overflowing", determineOverflow(pnProductNavContents, pnProductNav));

// Set the indicator
moveIndicator(pnProductNav.querySelector("[aria-selected=\"true\"]"), colours[0]);

// Handle the scroll of the horizontal container
var last_known_scroll_position = 0;
var ticking = false;

function doSomething(scroll_pos) {
    pnProductNav.setAttribute("data-overflowing", determineOverflow(pnProductNavContents, pnProductNav));
}

pnProductNav.addEventListener("scroll", function() {
    last_known_scroll_position = window.scrollY;
    if (!ticking) {
        window.requestAnimationFrame(function() {
            doSomething(last_known_scroll_position);
            ticking = false;
        });
    }
    ticking = true;
});


pnAdvancerLeft.addEventListener("click", function() {
	// If in the middle of a move return
    if (SETTINGS.navBarTravelling === true) {
        return;
    }
    // If we have content overflowing both sides or on the left
    if (determineOverflow(pnProductNavContents, pnProductNav) === "left" || determineOverflow(pnProductNavContents, pnProductNav) === "both") {
        // Find how far this panel has been scrolled
        var availableScrollLeft = pnProductNav.scrollLeft;
        // If the space available is less than two lots of our desired distance, just move the whole amount
        // otherwise, move by the amount in the settings
        if (availableScrollLeft < SETTINGS.navBarTravelDistance * 2) {
            pnProductNavContents.style.transform = "translateX(" + availableScrollLeft + "px)";
        } else {
            pnProductNavContents.style.transform = "translateX(" + SETTINGS.navBarTravelDistance + "px)";
        }
        // We do want a transition (this is set in CSS) when moving so remove the class that would prevent that
        pnProductNavContents.classList.remove("pn-ProductNav_Contents-no-transition");
        // Update our settings
        SETTINGS.navBarTravelDirection = "left";
        SETTINGS.navBarTravelling = true;
    }
    // Now update the attribute in the DOM
    pnProductNav.setAttribute("data-overflowing", determineOverflow(pnProductNavContents, pnProductNav));
});

pnAdvancerRight.addEventListener("click", function() {
    // If in the middle of a move return
    if (SETTINGS.navBarTravelling === true) {
        return;
    }
    // If we have content overflowing both sides or on the right
    if (determineOverflow(pnProductNavContents, pnProductNav) === "right" || determineOverflow(pnProductNavContents, pnProductNav) === "both") {
        // Get the right edge of the container and content
        var navBarRightEdge = pnProductNavContents.getBoundingClientRect().right;
        var navBarScrollerRightEdge = pnProductNav.getBoundingClientRect().right;
        // Now we know how much space we have available to scroll
        var availableScrollRight = Math.floor(navBarRightEdge - navBarScrollerRightEdge);
        // If the space available is less than two lots of our desired distance, just move the whole amount
        // otherwise, move by the amount in the settings
        if (availableScrollRight < SETTINGS.navBarTravelDistance * 2) {
            pnProductNavContents.style.transform = "translateX(-" + availableScrollRight + "px)";
        } else {
            pnProductNavContents.style.transform = "translateX(-" + SETTINGS.navBarTravelDistance + "px)";
        }
        // We do want a transition (this is set in CSS) when moving so remove the class that would prevent that
        pnProductNavContents.classList.remove("pn-ProductNav_Contents-no-transition");
        // Update our settings
        SETTINGS.navBarTravelDirection = "right";
        SETTINGS.navBarTravelling = true;
    }
    // Now update the attribute in the DOM
    pnProductNav.setAttribute("data-overflowing", determineOverflow(pnProductNavContents, pnProductNav));
});

pnProductNavContents.addEventListener(
    "transitionend",
    function() {
        // get the value of the transform, apply that to the current scroll position (so get the scroll pos first) and then remove the transform
        var styleOfTransform = window.getComputedStyle(pnProductNavContents, null);
        var tr = styleOfTransform.getPropertyValue("-webkit-transform") || styleOfTransform.getPropertyValue("transform");
        // If there is no transition we want to default to 0 and not null
        var amount = Math.abs(parseInt(tr.split(",")[4]) || 0);
        pnProductNavContents.style.transform = "none";
        pnProductNavContents.classList.add("pn-ProductNav_Contents-no-transition");
        // Now lets set the scroll position
        if (SETTINGS.navBarTravelDirection === "left") {
            pnProductNav.scrollLeft = pnProductNav.scrollLeft - amount;
        } else {
            pnProductNav.scrollLeft = pnProductNav.scrollLeft + amount;
        }
        SETTINGS.navBarTravelling = false;
    },
    false
);

// Handle setting the currently active link
pnProductNavContents.addEventListener("click", function(e) {
	var links = [].slice.call(document.querySelectorAll(".pn-ProductNav_Link"));
	links.forEach(function(item) {
		item.setAttribute("aria-selected", "false");
	})
	e.target.setAttribute("aria-selected", "true");
	// Pass the clicked item and it's colour to the move indicator function
	moveIndicator(e.target, colours[links.indexOf(e.target)]);
	console.log(colours[links.indexOf(e.target)]);
});

function moveIndicator(item, color) {
    var textPosition = item.getBoundingClientRect();
    var container = pnProductNavContents.getBoundingClientRect().left;
    var distance = textPosition.left - container;
    pnIndicator.style.transform = "translateX(" + (distance + pnProductNavContents.scrollLeft) + "px) scaleX(" + textPosition.width * 0.01 + ")";
    if (color) {
        pnIndicator.style.backgroundColor = color;
    }
}

function determineOverflow(content, container) {
    var containerMetrics = container.getBoundingClientRect();
    var containerMetricsRight = Math.floor(containerMetrics.right);
    var containerMetricsLeft = Math.floor(containerMetrics.left);
    var contentMetrics = content.getBoundingClientRect();
    var contentMetricsRight = Math.floor(contentMetrics.right);
    var contentMetricsLeft = Math.floor(contentMetrics.left);
	 if (containerMetricsLeft > contentMetricsLeft && containerMetricsRight < contentMetricsRight) {
        return "both";
    } else if (contentMetricsLeft < containerMetricsLeft) {
        return "left";
    } else if (contentMetricsRight > containerMetricsRight) {
        return "right";
    } else {
        return "none";
    }
}
              
            
!
999px

Console