Anpassen von Cross-Browser-Bereichseingaben mit CSS und JavaScript

Avatar of Steven Estrella
Steven Estrella am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der folgende Beitrag stammt von 2015 von Steven Estrella, den er gerade im Januar 2019 aktualisiert hat. Steven teilte mir eine Technik zur Erstellung benutzerdefinierter Bereichseingaben mit, indem er etwas JavaScript auf einige der hier von Daniel Stern und anderen untersuchten Techniken schrieb. Ich habe Steven eingeladen, seinen Ansatz zu erklären.

Guter Wein und gute Freundschaften altern gut. Code ist eine andere Sache. Dinge ändern sich und manchmal werden sie einfacher. Das alte CodePen von 2015 funktioniert immer noch, aber es verwendet einen Grad an Komplexität, der für die Bewältigung der anstehenden Aufgabe nicht mehr erforderlich ist. Also habe ich ein neues CodePen erstellt, um einen aktualisierten Ansatz zu veranschaulichen, und die guten Leute von CSS-Tricks gebeten, diesen Artikel aktualisieren zu dürfen.

Im Jahr 2014 schrieb Daniel Stern einen sehr nützlichen Artikel, um das browserübergreifende Styling der HTML5-Bereichseingabe nur mit CSS und HTML zu demonstrieren. Er hat sogar ein praktisches Tool namens range.css zur Generierung des CSS erstellt. Manchmal gehen unsere Designs jedoch über das hinaus, was mit CSS allein möglich ist.

Im folgenden Beispiel wollte ich mit dem experimentieren, was derzeit mit JavaScript möglich ist, wenn eine Bereichseingabe manipuliert wird

Siehe den Pen
Benutzerdefinierte Bereichseingabe mit CSS und JavaScript 2019
von Steven Estrella (@sgestrella)
auf CodePen.

Beachten Sie, wie die Spur mit einem Farbverlauf gefüllt wird, während Sie den Schieberegler ziehen? Außerdem verwendet der Schieberegler ein Bild als Hintergrund, dreht sich beim Ziehen und zeigt den Wert als Text an. Und natürlich gibt es die nicht ganz kleine Angelegenheit, sowohl horizontale *oder* vertikale Schieberegler-Ausrichtungen zu ermöglichen und Eingaben von der Tastatur beizubehalten. Wir werden das bald genauer erläutern. Letztendlich führt Sie dieses Tutorial durch den Code und die Konzepte, um diese Art der Kontrolle über das Erscheinungsbild und die Funktionalität von HTML5-Bereichseingaben hinzuzufügen.

Markieren

Unser Ansatz besteht darin, die Standard-Bereichseingabe für den Benutzer unsichtbar zu machen. Sie funktioniert weiterhin normal und ist genauso zugänglich, aber ihr Erscheinungsbild wird durch unsere eigenen gestylten Divs ersetzt. Dann werden wir sie alle mit etwa 50 Zeilen JavaScript miteinander verbinden. Wenn der Benutzer den unsichtbaren Schieberegler zieht, werden Ereignislistener ausgelöst, die eine Funktion aufrufen und den Wert der Bereichseingabe übertragen. Folglich löst dies Änderungen am Erscheinungsbild der gestylten Divs aus.

OK, fangen wir also mit dem Markup für eine einzelne Bereichseingabe an

<div class="rangewrapper horizontal">
  <div class="sliderfill">
  <input class="customrange" type="range" min="0" max="100" value="50">
  </div>
  <div class="sliderthumb"></div>
  <div class="slidervalue">50</div>
</div>
  • Das äußere `.rangewrapper`-Div dient als Positionierungskontext für die darin enthaltenen Divs. Die zweite angezeigte Klasse kann entweder horizontal oder vertikal sein.
  • `.sliderfill` wird mit einem Farbverlaufshintergrund versehen, der das Erscheinungsbild ändert, während der Benutzer den Schieberegler zieht.
  • `<input type="range">` ist das eigentliche Bereichseingabeelement, dem wir eine sehr geringe Deckkraft geben.
  • `.sliderthumb` erstellt das beveled, quadratische Bild im 90er-Jahre-Stil, das wie Marmor aussieht.
  • `.slidervalue` formatiert den aktuellen Wert der Schieberegler-Eingabe.
  • `.sliderthumb` und `.slidervalue` werden absolut positioniert und so eingestellt, dass sie keine Zeigerereignisse ignorieren.

In unserem Beispiel erstellen wir vier dieser `.rangewrapper`-Elemente, wobei das letzte für die vertikale Ausrichtung eingestellt ist. Ich habe die drei horizontalen Schieberegler innerhalb eines `<div class="rangepresenter">` gruppiert, der Struktur und Platz für eine Überschrift bietet. Ich habe den einzelnen vertikalen Schieberegler in `<div class="rangepresenter verticalsliders">` platziert. Beide Divs befinden sich innerhalb von `<article class="content">`, das mit Media Queries auf schmalen Bildschirmen als Raster mit 1 Spalte und auf größeren Bildschirmen mit 2 Spalten angezeigt wird. Sie können das vollständige CSS im Code-Pen sehen, aber hier sind die Highlights.

/* Modified Meyer Reset to smooth out browser differences*/
/* CSS variables to keep appearance consistent */
:root {
    /*variables for font color and other cosmetics*/
    /*variables for gradient color stops and sizing the sliders*/
    --accentcolor: rgb(0,128,128);
    --accentcoloralpha: rgba(0,128,128,0.5);
    --maxwidth: 800px;
    --lineheight: 1.3;
    --thumbsize: 40px;
    --tracksize: 300px;
    --trackheight: 28px;
    --trackradius: 6px;
    --innertrackradius: 4px;
}
/*Grid layout with media queries follows*/
/*Then cosmetic styles for the wrapper, headings, content, etc... */
/*Here is the heart of the matter.*/
.rangepresenter {
  width:var(--tracksize);
  height:auto;
}
/*The width is adjusted for vertical sliders and the height is specified.*/
/*Relative position is important to provide a positioning context for the 
vertical slider which will be rotated.*/
.rangepresenter.verticalsliders {
    max-width:calc(var(--tracksize)/2);
    min-height:calc(var(--tracksize) + 60px);
    position:relative;
 }
/*Relative position for rangewrapper is important to provide a positioning context 
for the thumb and value text. It also provides a background color for the slider track.*/
.rangewrapper {
  line-height:var(--lineheight);
  border:2px solid var(--maincolor);
  border-radius:var(--trackradius);
  margin:20px 0 40px 0;
  padding:0;
  position:relative;
  width:var(--tracksize);
  height:var(--trackheight);
  overflow:visible;
  background-color:#ffc;
}
/*The rangewrapper class is rotated when vertical. The position must then be 
calculated so it appears centered after the transformation.*/
.rangewrapper.vertical{
  transform-origin: 50% 50%;
  transform: rotate(-90deg);
  position:absolute;
  top:calc( (var(--tracksize)/2) + 30px);
  left:-50%;
  margin:0;
}
/*The border-radius for the inner fill of the slider track is just a bit smaller 
than the border-radius for the enclosing rangewrapper div.*/
.sliderfill {
  border:0 none;
  border-radius:var(--innertrackradius);
  margin:0;
  padding:0;
  height:100%;
}
/*The sliderthumb uses an image and it is absolutely position using a calculation. 
Pointer-events are set to none so it won't block dragging the range input thumb. 
We will use javascript to be sure the sliderthumb always appears at the same location 
as the real range input thumb.*/
.sliderthumb {
  width:var(--thumbsize);
  height:var(--thumbsize);
  background-image:url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/358203/thumb.png');
  background-size: 100% 100%;
  background-repeat: no-repeat;
  background-color:transparent;
  position:absolute;
  left:0;
  top:calc(((var(--thumbsize) - var(--trackheight))/-2) - 2px);
  border:0 none;
  padding:0;
  pointer-events:none;
}
/*The slidervalue displays the current value of the slider at all times and is 
positioned absolutely just like the sliderthumb.*/
.slidervalue {
  width:var(--thumbsize);
  height:var(--thumbsize);
  line-height:var(--thumbsize);
  position:absolute;
  left:calc(50% - (var(--thumbsize)/2));
  top:calc(((var(--thumbsize) - var(--trackheight))/-2) - 2px);
  color:white;
  font-family:var(--mainfont);
  font-size:1.1rem;
  font-weight:normal;
  border:0 none;
  pointer-events:none;
}
/*When the slider is vertical we need to compensate by rotating the text 90 degrees.*/
.vertical .slidervalue {
  transform:rotate(90deg);
}
/*The customrange class sets each range input to a low opacity.*/
.customrange {
  cursor:pointer;
  height:100%;
  width:var(--tracksize);
  opacity:0.05;
}

Das JavaScript

Schließlich können wir alles mit JavaScript zusammenfügen. Variablen werden erstellt, um die Objektverweise für die Schieberegler, Thumbnails, Füllungen und Werte zu speichern. Anfangswerte für die Schieberegler werden in einem Array platziert. Sobald das Dokument geladen ist, wird die init-Funktion aufgerufen und die Schieberegler werden aktualisiert, um das initialValue-Array widerzuspiegeln. Ereignislistener werden hinzugefügt, um auf Eingabe- und Änderungsereignisse bei den Bereichseingaben zu reagieren. Sie lösen die Funktion `updateSlider` aus, die einen Parameter für die Schieberegler-Nummer und einen zweiten Parameter für den im Bereichselement gewählten Wert erhält. Dann können wir mit etwas einfacher Mathematik den Wert verwenden, um den Schieberegler zu positionieren und zu drehen, den Wert als Text anzuzeigen und die Spur beim Ziehen des Schiebereglers mit einem Farbverlauf zu füllen.

let sliders, sliderfills, thumbs, slidervalues;
let initialValue = [38,50,63,88]; //initial values for the sliders

document.addEventListener('DOMContentLoaded', function (e) { init();});

function init(){
  sliders = document.querySelectorAll(".customrange");
  sliderfills = document.querySelectorAll(".sliderfill");
  thumbs = document.querySelectorAll(".sliderthumb");
  slidervalues = document.querySelectorAll(".slidervalue");
  /* We need to change slider appearance to respond to both input and change events. */
  for (let i=0;i<sliders.length;i++){
    sliders[i].addEventListener("input",function(e){
      updateSlider(i,sliders[i].value);});
    sliders[i].addEventListener("change",function(e){
      updateSlider(i,sliders[i].value);});
    //set initial values for the sliders
    sliders[i].value = initialValue[i];
    //update each slider
    updateSlider(i,sliders[i].value);
  }
}
function updateSlider(fillindex,val){
  //sets the text display and location for each thumb and the slider fill  
  setThumbText(slidervalues[fillindex],val);
  setThumb(thumbs[fillindex],val);
  setSliderFill(sliderfills[fillindex],val);
}
function setThumbText(elem,val){
  let size = getComputedStyle(elem).getPropertyValue("--thumbsize");
  let newx = `calc(${val}% - ${parseInt(size)/2}px)`;
  elem.style.left = newx;
  elem.innerHTML = val;
}
function setThumb(elem,val){
  let size = getComputedStyle(elem).getPropertyValue("--thumbsize");
  let newx = `calc(${val}% - ${parseInt(size)/2}px)`;
  elem.style.left = newx;
  let degrees = 360 * (val/100);
  let rotation = `rotate(${degrees}deg)`;
  console.log(rotation);
	elem.style.transform = rotation;
}
function setSliderFill(elem,val){
  let fillcolor = getComputedStyle(elem).getPropertyValue("--accentcolor");
  let alphafillcolor = getComputedStyle(elem).getPropertyValue("--accentcoloralpha");
  // we create a linear gradient with a color stop based on the slider value
  let gradient = `linear-gradient(to right, ${fillcolor} 0%, 
${alphafillcolor} ${val}%, 
rgba(255,255,255,0.1) ${Number(val) + 1}%, 
rgba(255,255,255,0)  100%)`;
  elem.style.backgroundImage = gradient;
}

Zusammenfassung

Lange Zeit war das Styling von Eingaben übermäßig schwierig. Aber jetzt, mit ein wenig CSS und JavaScript, können wir diese Probleme in allen modernen Browsern beheben, ohne die heroischen Anstrengungen, die in der Vergangenheit erforderlich waren.

Weitere Informationen