Tag Archives: Cross-browser

Customising Cross-Browser Range Inputs with CSS and JavaScript

Customising Cross-Browser Range Inputs with CSS and JavaScript
// CSS-Tricks

The following is a guest post by Steven Estrella. Steven shared with me a technique for creating customized range inputs by writing a little JavaScript atop some of the techniques explored here by Daniel Stern and others. I invited Steven to explain his approach.

Last year, Daniel Stern wrote a very useful article to demonstrate cross-browser styling of the HTML5 range input using nothing more than CSS and HTML. He even created a handy tool called range.css for generating the CSS. Sometimes, however, our designs may need to go beyond what is possible with CSS alone.

In the example below I wanted to experiment with what’s currently possible when manipulating a range input with JavaScript:

See the Pen 17140bb5973a773b82e2d5fd1d5bcd00 by CSS-Tricks (@css-tricks) on CodePen.

Notice how the track fills with a gradient as you drag the thumb? Also, the thumb uses an image as its background, rotates whilst you drag, and displays the value as text. And of course there is the not-so-small-matter of allowing for both horizontal or vertical slider orientations and preserving inputs from the keyboard too. We’ll go into further detail on that soon. Ultimately, this tutorial will walk you through the code and concepts to add this type of control over the appearance and functionality of HTML5 range inputs.

Marking things up

To get started, we’ll make the standard range input invisible to the user, place it on top of our own styled divs, and then wire them all together with a few lines of JavaScript. The user will then drag the invisible range input thumb, which will fire event listeners that call a function and transmit the range input value. Consequently, this will trigger changes to the appearance of the styled divs.

OK, so let’s start with the markup first:

<table class="slider2column"> <tr> <td>

<input class=”slider” id=”slider1″ type=”range” min=”0″ max=”100″ value=”0″ /> </div> </td> </tr> </table>

  • The outer .slidershell div exists to provide a positioning context for the divs it contains.
  • .sliderfill should create a gradient that changes the appearance as the user drags the thumb.
  • .slidertrack will display a styled border on top of the .sliderfill.
  • .sliderthumb makes the 90’s-style beveled square image that looks like marble.
  • .slidervalue styles the current value of the slider input.

Finally, the <input type="range"> is added last so that it rests on top of those other elements.

In our example we’ll need to have three of these td elements, with each input having an id attribute with a different number at the end. This will allow us to present multiple sliders in both orientations on the same page. At the moment our input will look like this:

See the Pen a823e1cf9e505f812f01fe9d6016e441 by CSS-Tricks (@css-tricks) on CodePen.

Next, we can add an inline event listener to call a JavaScript function when the slider has an input or registers a change in the value. The function should take three parameters: the value of the slider, the number of the slider, and a boolean value of true if the slider should be vertical. We’ll call this function showValue():

<input class="slider" id="slider1" type="range" min="0" max="100" value="0" oninput="showValue(value, 1, false);" onchange="showValue(value, 1, false);" />

Now we have to strip away the default appearance of the range input with some CSS that effectively acts as a reset. We can do this by first adapting the ideas presented by Daniel Stern, but then focus our efforts on making all the default elements of the range input appear transparent.

/* First we have to make transparent all the default elements of the range input. We use color:transparent to eliminate the default tick marks in IE. */ input[type=range]::-ms-track { width: 100%; height: 100%; -webkit-appearance: none; margin: 0px; padding: 0px; border: 0 none; background: transparent; color: transparent; overflow: visible; } input[type=range]::-moz-range-track { width: 100%; height: 100%; -moz-appearance: none; margin: 0px; padding: 0px; border: 0 none; background: transparent; color: transparent; overflow: visible; } input[type=range] { width: 100%; height: 100%; -webkit-appearance: none; margin: 0px; padding: 0px; border: 0 none; background: transparent; color: transparent; overflow: visible; } input[type=range]:focus::-webkit-slider-runnable-track { background: transparent; border: transparent; } input[type=range]:focus { outline: none; } /* Make the thumbs the same size as your custom sliderthumb. They will not be visible but they will be draggable. */ input[type=range]::-ms-thumb { width: 40px; height: 40px; border-radius: 0px; border: 0 none; background: transparent; } input[type=range]::-moz-range-thumb { width: 40px; height: 40px; border-radius: 0px; border: 0 none; background: transparent; } input[type=range]::-webkit-slider-thumb { width: 40px; height: 40px; border-radius: 0px; border: 0 none; background: transparent; -webkit-appearance: none; } /* Eliminate the default appearance and tooltip behaviour that is peculiar to IE and Edge. */ input[type=range]::-ms-fill-lower { background: transparent; border: 0 none; } input[type=range]::-ms-fill-upper { background: transparent; border: 0 none; } input[type=range]::-ms-tooltip { display: none; }

At this point, if you reload your example, you’ll find that the default range elements will now be hidden. Notice also that the width and height are set to 100% of its containing element (the .slidershell class in our example). However, the CSS for the thumb pseudo-elements requires us to enter a specific width and height in pixels. These dimensions should match the size of whatever image you plan to use for the thumb because we must ensure that the draggable area of the invisible range input matches the size of the visible thumb image.

Next, we can choose an image to use for the draggable thumb. I selected an old 90s-style library image of a green marble beveled square:

Following this, we can style our customized range input to look however we’d like:

/* The .slider and .slidervertical classes are for the range inputs. Set the z-index high so its on top. */ .slider, .slidervertical { position: absolute; left: 0; top: 0; overflow: visible; z-index: 100; } /* slidershell exists only to provide a positioning context for the range input and other elements.*/ .slidershell { border: 0 none; position: relative; left: 0; top: 0; overflow: visible; } /* .slidertrack is the visible track on which the user drags the thumb button. */ .slidertrack { border: 2px outset #666; border-radius: 4px; position: absolute; } /* .sliderfill adds color (or a gradient as seen here) to the track as the user drags the thumb. */ .sliderfill { border: 2px solid #00767f; border-radius: 4px; position: absolute; opacity: 0.2; pointer-events: none; background: #00767f; background: linear-gradient(90deg, #005555, #006699); } /* .sliderthumb can be any css you like including an image. The dimensions must match those found in the rule for input[type=range]::-webkit-slider-thumb. */ .sliderthumb { width: 40px; height: 40px; background-image: url('thumb.png'); background-size: 40px 40px; background-position: 0px 0px; background-repeat: no-repeat; background-color: transparent; position: absolute; left: 0; top: 0; border: 0 none; padding: 0; margin: 0; text-align: center; pointer-events: none; } /* .slidervalue can be styled as you see fit */ .slidervalue { width: 40px; height: 40px; line-height: 40px; color: #fff; font-family: sans-serif; font-size: 18px; position: absolute; left: 0; top: 0; border: 0 none; padding: 0; margin: 0; text-align: center; pointer-events: none; }

Finally, we can tie everything together with JavaScript. The showValue function receives a parameter representing the value chosen in the range element and a second parameter representing the slider number. The third parameter is a boolean to indicate vertical orientation if true. We can have as many sliders as we want on one page, all we need to do is give them each a serialized id (#sliderthumb1, #sliderthumb2, etc.). Then, with some simple math, we can use the value to locate and rotate the thumb, display the value as text, and fill the track with color as the user drags the thumb. A series of inline if structures allows us to support vertical orientation when requested. I also included a setValue() function you can use to set the values of your sliders when the page loads.

/* We need to change slider appearance oninput and onchange */ function showValue(val,slidernum,vertical) { /* setup variables for the elements of our slider */ var thumb = document.getElementById("sliderthumb" + slidernum); var shell = document.getElementById("slidershell" + slidernum); var track = document.getElementById("slidertrack" + slidernum); var fill = document.getElementById("sliderfill" + slidernum); var rangevalue = document.getElementById("slidervalue" + slidernum); var slider = document.getElementById("slider" + slidernum); var pc = val/(slider.max - slider.min); /* the percentage slider value */ var thumbsize = 40; /* must match the thumb size in your css */ var bigval = 250; /* widest or tallest value depending on orientation */ var smallval = 40; /* narrowest or shortest value depending on orientation */ var tracksize = bigval - thumbsize; var fillsize = 16; var filloffset = 10; var bordersize = 2; var loc = vertical ? (1 - pc) * tracksize : pc * tracksize; var degrees = 360 * pc; var rotation = "rotate(" + degrees + "deg)"; rangevalue.innerHTML = val; thumb.style.webkitTransform = rotation; thumb.style.MozTransform = rotation; thumb.style.msTransform = rotation; fill.style.opacity = pc + 0.2 > 1 ? 1 : pc + 0.2; rangevalue.style.top = (vertical ? loc : 0) + "px"; rangevalue.style.left = (vertical ? 0 : loc) + "px"; thumb.style.top = (vertical ? loc : 0) + "px"; thumb.style.left = (vertical ? 0 : loc) + "px"; fill.style.top = (vertical ? loc + (thumbsize/2) : filloffset + bordersize) + "px"; fill.style.left = (vertical ? filloffset + bordersize : 0) + "px"; fill.style.width = (vertical ? fillsize : loc + (thumbsize/2)) + "px"; fill.style.height = (vertical ? bigval - filloffset - fillsize - loc : fillsize) + "px"; shell.style.height = (vertical ? bigval : smallval) + "px"; shell.style.width = (vertical ? smallval : bigval) + "px"; track.style.height = (vertical ? bigval - 4 : fillsize) + "px"; /* adjust for border */ track.style.width = (vertical ? fillsize : bigval - 4) + "px"; /* adjust for border */ track.style.left = (vertical ? filloffset + bordersize : 0) + "px"; track.style.top = (vertical ? 0 : filloffset + bordersize) + "px"; } /* we often need a function to set the slider values on page load */ function setValue(val,num,vertical) { document.getElementById("slider"+num).value = val; showValue(val,num,vertical); }

Making vertical inputs

To make those vertical inputs we mentioned earlier we can set the third parameter of the showValue() function to true and add orient="vertical" to the input itself, like so:


<input class=”slidervertical” id=”slider3″ type=”range” min=”0″ max=”100″ value=”0″ oninput=”showValue(value,3,true);” onchange=”showValue(value,3,true);” orient=”vertical” /> </div> </td>

The orient="vertical" attribute is only supported by Firefox, so to fix this we’ll need to update our CSS:

/* we need a separate rule for when the range input is to be vertical */ input[type=range].slidervertical { -webkit-appearance: slider-vertical; writing-mode: bt-lr; /* IE */ opacity:0.01; /* needed to hide the default slider-vertical appearance */ }

Because we have to use -webkit-appearance: slider-vertical, we have to set the opacity to 0.01 here to keep the vertical slider invisible. And here’s what that additional markup and CSS will look like:

See the Pen 840d5006ed127be58f30e1891b4698af by CSS-Tricks (@css-tricks) on CodePen.

Wrapping up

For the longest time styling inputs was beyond challenging. But now, with a little CSS and JavaScript, we can fix these problems in all modern browsers without the heroic efforts required in the past.

More information

Continuous Delivery Testing Pathway

This pathway is a tool to help guide your self development in continuous delivery testing. It includes a variety of steps that you may approach linearly or by hopping about to those that interest you most.

Each step includes:

  • links to a few resources as a starting point, but you are likely to need to do your own additional research as you explore each topic.
  • a suggested exercise or two, which focus on reflection, practical application and discussion, as a tool to connect the resources with your reality.

Take your time. Dig deep into areas that interest you. Apply what you learn as you go.

STEP – Removing release testing

Why does this pathway exist? Understand the key reasons to significantly shorten a release process, the arguments against release testing and why organisations aim to avoid batched releases in agile environments:

[2 hours] Research your existing release process and talk to people within your organisation to find out whether there are any current initiatives to improve it.

STEP – Introduction to continuous delivery

What is the end goal? Discover the basics of continuous delivery and the theory of how it can be implemented in organisations.

[1 hour] Based on what you’ve read, try to explain the theory of continuous delivery in your own words to someone in your team. Describe what appeals to you about continuous delivery, what you disagree with, and things that you think will be difficult to implement in your organisation. Afterwards, if you have any remaining questions, raise these with a technical lead or coach for further discussion.

STEP – Experiences in continuous delivery

How are other organisations doing continuous delivery? There is a lot of variance in implementation and differing opinions about how to approach the theory. Understand the realities of the people, processes and tools of teams doing continuous delivery:

[2 hours] Compare the experiences shared in the links above and the theory of continuous delivery. Identify common themes, and areas where ideas or implementation details differ. Discuss your analysis with a technical lead or coach.

STEP – Starting with continuous integration

What is the first step? Understand the concept of continuous integration:

[3 hours] At the start of this talk transcript, Jez Humble points out that most people aren’t doing continuous integration. How does the approach to continuous integration in your team differ to the theory? Talk to a developer to confirm your understanding of your branching strategy, the way you use source control management tools, and how you manage merging to master. If you use a continuous integration tool, create a list of the jobs that are used by your team during development, and be sure that you understand what each one does. Reflect on how quickly your team respond to build failures in these jobs, and who takes ownership for resolving these. Discuss this exercise with a technical lead or coach to collaboratively identify opportunities for improvement, then raise these ideas at your next team retrospective.

STEP – Theory of test automation

Continuous delivery puts a lot of focus on test automation. In order to support development of an effective pipeline it’s important to understand common strategies for automation, and the distinction between checking and testing:

[1 hour] Read through the automation strategy for your product. How well does your existing strategy for automation support your delivery pipeline? What opportunities exist to improve this strategy? Discuss your thoughts with a technical lead or coach.

STEP – A delivery pipeline

Understand how to construct delivery pipeline and the role of automation:

[3 hours] Create a visual representation of the current delivery pipeline for your product. Use a timeline format that shows the build jobs in your continuous integration tool at every stage from development through to production deploy, any test jobs that execute automated suites, and points where the tester is hands-on, exploring the product. Compare your pipeline to the simplified images by Yassal Sundman forcontinuous delivery and continuous deployment, then reflect on the following questions:

  1. How would your approach to testing change, or not, if we were able to deploy to production 10 times a day? How about 100 times a day?
  2. Does the coverage provided by your automation give you a degree of comfort or confidence? If not, what needs to change?
  3. Does your automation execute fast enough? How fast do you think it should be? How can you achieve this?
  4. Where in the pipeline would you want to retain hands-on testing? How would you justify this?

Discuss your ideas with a technical lead or coach. Work together to identify actions from your thinking and determine how to proceed in implementing change.

STEP – Non-functional testing in continuous delivery

Learn more about integrating security, performance, and other non-functional testing in a continuous delivery pipeline:

[2 hours] Does your organisation have a non-functional testing “sandwich”? Having read more about organisations who integrate these activities earlier in the process, what opportunities do you see to improve the way that you work? What would the first steps be? Talk to a technical lead or coach about what you’d like to see change.

STEP – Cross-browser testing

For continuous delivery of a web application, it’s important to include cross-browser testing in the delivery pipeline. Discover strategies for cross-browser testing and the tools available to support it:

[8 hours] Learn more about the common cross-browser tools that are available, understand the advantages and disadvantages of each option, then select a tool to trial. Create a prototype to execute existing browser-based automation for your product across multiple browsers. If successful on your local environment, attempt to create a prototype job in your continuous integration tool to verify that your chosen solution works as part of your continuous integration. Discuss what you learned about the tool and the results of your experiment with a technical lead or coach.

STEP – Test data & databases

Discover the additional considerations around test data in continuous delivery:

[1 hour] Data is a constant headache for testers. Consider the limitations of the test data in use by your automation. How could you improve the data within your delivery pipelines? How could you improve the way that you locate data for testing? Talk through your ideas with a technical lead or coach.

STEP – Configuration management & environments

An effective delivery pipeline is supported by multiple test environments. Learn more about configuration management, environments and infrastructure services in continuous delivery:

[1 hour] Talk to your operations or support team about how they provide test environments for continuous integration, the infrastructure required to support a delivery pipeline, and what their plans are for future changes in this space.

STEP – Testing in production

Understand A/B testing and feature toggles:

[1 hour] Talk to people in your organisation to find out how you currently use feature toggles and how you make decisions about what to keep based on user analytics. Could your approach be more responsive through targeted use of a monitoring tool like splunk? Share your thoughts with a technical lead or coach.

MatchDimension: Cross browser Javascript viewport awareness

via milosdjakonovic/MatchDimension · GitHub.

Cross browser Javascript viewport awareness

Small library aimed to provide Javascript viewport awareness across all browsers, event those noncompliant to standards, that do not support CSS media queries natively.

  • No dependency
  • Works across every A and not so A grade browser (even in IE6 and Android 2.1 browser)
  • Lightweight and very fast (~1.7KB minified)
  • Takes advantage of native matchMedia functionality when available
  • Takes possible window resize or orientation change into count
  • Option to listen for viewport changes – bind functions on resize and orientationchange events – like matchMedia.addListener
  • Simple to write, less chars

Enhance your JavaScript Debugging Life with Cross-browser Source Maps

via Enhance your JavaScript Debugging Life with Cross-browser Source Maps | NOUPE.

As a JavaScript developer, I’m sure you’ve already been falling into this scenario: something goes wrong with the production version of your code, and debugging it directly from the production server is a nightmare simply because it has been minified or has been compiled from another language such as TypeScript or CoffeeScript.