html - can we make simple bar chart with basic html and css - html

I have done this right now with html/css only. But problem is I have used position - relative for outer bar and position absolute for inner item's placement. But as the text gets big/small the positioning isnt center (text below or above charts)
And if I dont use position on elements, the texts below graph floats on top or above that. Also the amount showing up just above chart goes in straight line.
<div class="bar-container">
<div class="fl width-100 r">
<div class="donut-bg width-100 fl mr-c">
<div class="bar" ng-repeat="d in barData track by $index" style="margin: 0 {{chartData.marginRight}}%">
<div class="bar-value" style="bottom: {{+d.perc+20}}%">{{d.value}}K</div>
<div class="bar-chart" style="height: {{d.perc}}%;"></div>
<div class="bar-name c">d.text</div>
</div>
</div>
</div>
</div>
barData = [{"value":33,"text":"AU","perc":"35.36","padPerc":"39.64"},{"value":0,"text":"BD","perc":"0.00","padPerc":"75.00"},{"value":0,"text":"DB","perc":"0.00","padPerc":"75.00"},{"value":11,"text":"ED","perc":"11.79","padPerc":"63.21"},{"value":70,"text":"EI","perc":"75.00","padPerc":"0.00"}]

I have done something like this with HTML, CSS and PHP in the past - maybe this gives you an idea:
diagram.css
#diagram
{
position: relative;
padding: 0;
border: 1px solid #000;
font-family: verdana;
background: #fff;
}
#diagram div.title
{
padding: 0;
position: relative;
font: 12px;
font-weight: bold;
text-align: center;
line-height: 15px;
top: 5px;
}
#diagram div.axis
{
padding: 0;
position: absolute;
top: 50px;
left: 50px;
border-bottom: 1px solid black;
border-left: 1px solid black;
}
#diagram div.xunit
{
padding: 0;
position: absolute;
font-size: 8px;
text-align: center;
left: 50px;
// border: 1px solid black;
}
#diagram div.yunit
{
padding: 0;
position: absolute;
top: 25px;
left: 25px;
font-size: 8px;
text-align: left;
// border: 1px solid black;
}
#diagram div.xlabels
{
padding: 0;
position: absolute;
left: 50px;
height: 25px;
line-height: 25px;
// border: 1px solid #000;
}
#diagram div.xlabel
{
position: absolute;
left: 0;
height: 25px;
padding: 0;
font-size: 8px;
color: #c00;
// border: 1px solid #000;
}
#diagram div.ylabels
{
padding: 0;
position: absolute;
top: 50px;
left: 25px;
width: 25px;
// line-height: 25px;
// border: 1px solid #000;
}
#diagram div.ylabel
{
position: absolute;
left: 0;
width: 25px;
padding: 0;
font-size: 8px;
color: #c00;
// border: 1px solid #000;
}
#diagram div.bar
{
position: absolute;
text-align: right;
font-size: 10px;
color: #fff;
font-weight: bold;
border: 1px solid #000;
padding: 0px 0 0 0;
background: #c00;
}
diagram1.thtml
<!DOCTYPE html>
<html lang="de">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="diagram.css">
</head>
<body>
<div id="diagram" style="width: {DIAGRAMWIDTH}px; height: {DIAGRAMHEIGHT}px;">
<div class="title">{DIAGRAMTITLE}
<form id="diagramform" action="/diagram1.php" method="get">
<input type="text" id ="startcell" name="startcell" value="{DIAGRAMSTARTCELL}" /> - <input type="text" id ="endcell" name="endcell" value="{DIAGRAMENDCELL}" />
<!-- <button type="button" onclick=""><</button> --> <input type="text" id ="date" name="date" value="{DIAGRAMDATE}" /> <button type="button" onclick="var formdate = document.getElementById('date'); var nextdate = new Date(formdate.value); nextdate.setTime(nextdate.getTime() + 1000); formdate.value = nextdate.getFullYear() + '-' + (nextdate.getMonth() + 1) + '-' + nextdate.getDate() + ' ' + nextdate.getHours() + ':' + nextdate.getMinutes() + ':' + nextdate.getSeconds(); document.getElementById('diagramform').submit();">></button>
<input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;" tabindex="-1" />
</form>
</div>
<div class="axis" style="width: {AXISWIDTH}px; height: {AXISHEIGHT}px;">
<div class="bar">
<!-- BEGIN XBAR_POS -->
<div class="bar" style="width: {XBAR_WIDTH}px; left: {XBAR_LEFT}px; top: {XBAR_TOP}px; height: {XBAR_HEIGHT}px;"></div>
<!-- END XBAR_POS -->
</div>
</div>
<div class="xunit" style="top: {XLABEL_TOP}px; width: {XLABEL_WIDTH}px;">{XLABEL}</div>
<div class="yunit" style="height: {YLABEL_HEIGHT}px;">{YLABEL}</div>
<div class="xlabels" style="top: {XLABELS_TOP}px; width: {XLABELS_WIDTH}px;">
<!-- BEGIN XLABEL_POS -->
<div class="xlabel" style="left: {XLABEL_VALUE_LEFT}px;">{XLABEL_VALUE}</div>
<!-- END XLABEL_POS -->
</div>
<div class="ylabels" style="height: {YLABELS_HEIGHT}px;">
<!-- BEGIN YLABEL_POS -->
<div class="ylabel" style="top: {YLABEL_VALUE_TOP}px;">{YLABEL_VALUE}</div>
<!-- END YLABEL_POS -->
</div>
</div>
<hr />
Zellenübersicht | Zeitübersicht | Datenübermittlung
</body>
</html>
diagram1.php
<?php
require_once('HTML/Template/PHPLIB.php');
require_once('config.php');
$diagramdate = htmlspecialchars(#$_GET["date"]);
if (empty($diagramdate))
{
$diagramdate = date("Y-m-d");
}
$lasttimestamp = $diagramdate;
$diagramstartcell = htmlspecialchars(#$_GET["startcell"]);
if (empty($diagramstartcell))
{
$diagramstartcell = 1;
}
$diagramendcell = htmlspecialchars(#$_GET["endcell"]);
if (empty($diagramendcell))
{
$diagramendcell = 12;
}
$diagramwidth = 1000;
$diagramheight = 500;
$diagramtitle = 'Zellenübersicht';
$xlabels = array();
$mysqli = mysqli_connect($dbhost, $dbuser, $dbpasswd, $dbschema);
if ($mysqli->connect_errno)
{
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
$res = mysqli_query($mysqli, "select cell_id, cv_volt, cv_time from cell_voltages where cell_id >= " . $diagramstartcell . " and cell_id <= " . $diagramendcell . " and cv_time >= '" . $diagramdate . "' order by cv_time, cell_id"); // TODO prevent sql injection, use prepared statement
if ($res)
{
while ($row = $res->fetch_assoc())
{
if (isset($xlabels[$row['cell_id']]))
{
break;
}
$xlabels[$row['cell_id']] = $row['cv_volt'];
$lasttimestamp = $row['cv_time'];
}
$res->free();
}
$mysqli->close();
$ylabels = array(4.2, 4.0, 3.5, 3.0, 2.5, 2.0, 1.7);
// ----------
$axiswidth = $diagramwidth - 100;
$axisheight = $diagramheight - 100;
$xlabel_top = $diagramheight - 25;
$xlabel_width = $axiswidth;
$xlabel = 'Zellen';
$xlabels_top = $diagramheight - 50;
$xlabels_width = $axiswidth;
$ylabel_height = $axisheight + 25;
$ylabel = 'V';
$ylabels_height = $axisheight;
header('Content-Type: text/html; charset=utf-8');
$t = new HTML_Template_PHPLIB(dirname(__FILE__), 'keep');
$t->setFile('diagram', 'diagram1.thtml');
$t->setVar('DIAGRAMWIDTH', $diagramwidth);
$t->setVar('DIAGRAMHEIGHT', $diagramheight);
$t->setVar('DIAGRAMTITLE', $diagramtitle);
$t->setVar('DIAGRAMDATE', $lasttimestamp);
$t->setVar('DIAGRAMSTARTCELL', $diagramstartcell);
$t->setVar('DIAGRAMENDCELL', $diagramendcell);
$t->setVar('AXISWIDTH', $axiswidth);
$t->setVar('AXISHEIGHT', $axisheight);
$t->setVar('XLABEL_TOP', $xlabel_top);
$t->setVar('XLABEL_WIDTH', $xlabel_width);
$t->setVar('XLABEL', $xlabel);
$t->setVar('XLABELS_TOP', $xlabels_top);
$t->setVar('XLABELS_WIDTH', $xlabels_width);
$t->setVar('YLABEL_HEIGHT', $ylabel_height);
$t->setVar('YLABEL', $ylabel);
$t->setVar('YLABELS_HEIGHT', $ylabels_height);
$t->setBlock('diagram', 'XLABEL_POS', 'XLABEL_POS_ref');
if (count($xlabels) > 0)
{
$xpixelscale = $axiswidth / count($xlabels);
}
else
{
$xpixelscale = 1;
}
$i = 0;
foreach($xlabels as $xkey => $xvalue)
{
$t->setVar('XLABEL_VALUE', $xkey);
$t->setVar('XLABEL_VALUE_LEFT', ($xpixelscale * $i++) + ($xpixelscale / 2));
$t->parse('XLABEL_POS_ref', 'XLABEL_POS', true);
}
if ($i == 0)
{
$t->setVar('XLABEL_VALUE', '');
$t->setVar('XLABEL_VALUE_LEFT', 0);
$t->parse('XLABEL_POS_ref', 'XLABEL_POS', false);
}
$t->setBlock('diagram', 'YLABEL_POS', 'YLABEL_POS_ref');
$topvalue = reset($ylabels);
$bottomvalue = end($ylabels);
$ypixelscale = $axisheight / ($topvalue - $bottomvalue);
foreach($ylabels as $yvalue)
{
$t->setVar('YLABEL_VALUE', $yvalue);
$t->setVar('YLABEL_VALUE_TOP', $axisheight - (($yvalue - $bottomvalue) * $ypixelscale));
$t->parse('YLABEL_POS_ref', 'YLABEL_POS', true);
}
$t->setBlock('diagram', 'XBAR_POS', 'XBAR_POS_ref');
$i = 0;
foreach($xlabels as $xkey => $xvalue)
{
if ($xvalue - $bottomvalue >= 0)
{
$t->setVar('XBAR_WIDTH', $xpixelscale / 2);
$t->setVar('XBAR_LEFT', ($xpixelscale * $i) + ($xpixelscale / 4));
$t->setVar('XBAR_HEIGHT', ($xvalue - $bottomvalue) * $ypixelscale);
$t->setVar('XBAR_TOP', $axisheight - (($xvalue - $bottomvalue) * $ypixelscale));
$t->parse('XBAR_POS_ref', 'XBAR_POS', true);
}
++$i;
}
if ($i == 0)
{
$t->setVar('XBAR_WIDTH', '0');
$t->setVar('XBAR_LEFT', '0');
$t->setVar('XBAR_HEIGHT', '0');
$t->setVar('XBAR_TOP', '0');
$t->parse('XBAR_POS_ref', 'XBAR_POS', false);
}
echo $t->finish($t->parse('OUT', 'diagram'));
?>
The config.php has been left out, the TemplateEngine is the Pear version from PHPLib. Sorry no time to create a screenshot.

Related

How to set all element to left side with window scroll-down?

.be-ready-list {margin: 0px -24px;}
.be-ready-section{background-color:#eeeff3;padding:80px 0px 24px;}
.be-ready-section.complete-be-ready{background-color:#222222;}
.be-ready-list ul li{color:#FFFFFF;font-family:Poppins;font-size:32px;font-weight:500;letter-spacing:1.6px;line-height:24px;margin-bottom:32px;text-transform:uppercase;}
.be-ready-list ul li span {display: inline-block;vertical-align: top;padding: 16px 24px; background-color: #222222;}
.be-ready-list ul li:last-child{margin-bottom:0px;}
.we-are-hire{background-color:#222222;color:#ffffff;font-size:24px;font-weight:300;padding:40px 0px 96px;}
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<section class="be-ready-section">
<div class="wrapper">
<div class="be-ready-list">
<ul>
<li><span>Be ready for change</span></li>
<li><span>Set goals at home & work</span></li>
<li><span>Realize your unique value</span></li>
<li><span>Tame uncertainity</span></li>
<li><span>Lead with confidence</span></li>
<li><span>Addapt your business</span></li>
</ul>
</div>
</div>
</section>
</body>
</html>
Initial position ( This will initial position of elements )
Final position ( What i require when window scroll down)
I want animation on window scroll down. If window scroll down element will shift left side slowly , and when window will more scroll down elements will more move left side slowly. When this section will full on screen animation will done and Final position will appear.
const ul = document.getElementById("list-group");
const items = ul.getElementsByTagName("li");
init();
function init() {
for (var i = 0; i < items.length; ++i) {
animate(i, 100 * i);
}
}
window.addEventListener(
"scroll",
() => {
const size = window.pageYOffset;
if (window.pageYOffset) {
const i = parseInt(size / 75);
if (i === 0) init();
animate(i, 0);
}
},
false
);
function animate(index, margin) {
items[index].style.marginLeft = margin + 'px';
items[index].style.transition = '1s';
items[index].style.left = '0';
}
.be-ready-list {
margin: 250px 0;
}
.be-ready-section {
background-color: #eeeff3;
padding: 80px 0px 24px;
}
.be-ready-section.complete-be-ready {
background-color: #222222;
}
.be-ready-list ul li {
color: #FFFFFF;
font-family: Poppins;
font-size: 32px;
font-weight: 500;
letter-spacing: 1.6px;
line-height: 24px;
margin-bottom: 32px;
transition: 1s;
left: 0;
}
.be-ready-list ul li span {
display: inline-block;
vertical-align: top;
padding: 16px 24px;
background-color: #222222;
}
.be-ready-list ul li:last-child {
margin-bottom: 0px;
}
.we-are-hire {
background-color: #222222;
color: #ffffff;
font-size: 24px;
font-weight: 300;
padding: 40px 0px 96px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>animation example</title>
</head>
<body>
<section class="be-ready-section">
<div class="wrapper">
<div class="be-ready-list">
<ul id="list-group">
<li><span>Be ready for change</span></li>
<li><span>Set goals at home & work</span></li>
<li><span>Realize your unique value</span></li>
<li><span>Tame uncertainity</span></li>
<li><span>Lead with confidence</span></li>
<li><span>Addapt your business</span></li>
</ul>
</div>
</div>
</section>
</body>
</html>
function isScrolledIntoView(el) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elTop = $(el).offset().top;
var elBottom = elTop + $(el).height();
return (((elTop >= docViewTop) && (elTop <= docViewBottom)) || ((elBottom >= docViewTop) && (elBottom <= docViewBottom)));
}
function onScrollRezizeLoad() {
document.querySelectorAll('.be-ready-list div').forEach(el => {
if (isScrolledIntoView(el) && !el.classList.contains('on-left')) {
el.classList.add('on-left');
el.classList.add('skewed');
setTimeout(() => el.classList.remove('skewed'), 670);
}
});
}
onload = onScrollRezizeLoad;
onresize = onScrollRezizeLoad;
onscroll = onScrollRezizeLoad;
body {
margin: 0px;
padding: 0px;
overflow-x: hidden;
}
section.be-ready-section {
margin: -8px 0px 0px 0px;
padding: 8px;
width: 100vw;
background-color: #eeeff3;
}
.be-ready-list div {
background-color: #222222;
width: calc(100vw - 52px);
color: white;
font-size: 50px;
height: 300px;
/*remove this later just for demo purposes*/
font-weight: 300;
padding: 9px;
margin: 8px;
margin-left: calc(100vw - 150px);
transition: 1s, transform 0.67s;
}
div.on-left {
margin-left: 8px;
}
.skewed {
transform: skew(6deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section class="be-ready-section">
<div class="wrapper">
<div class="be-ready-list">
<div>Thing number 1</div>
<div>Thing number 2</div>
<div>Thing number 3</div>
<div>Thing number 4</div>
<div>Thing number 5</div>
<div>Thing number 6</div>
</div>
</div>
</section>
you could do something like this:
Use position relative and center them right in a div.
And use a modified version of this:
let elements = [
document.getElementById("e1"),
document.getElementById("e2"),
document.getElementById("e3")
]
// f(x) = mx
// (element.y;0) (element.y+viewport.height;viewport.width)
let ms = []
for (let i = 0; i < elements.length; i++) {
ms.push((document.documentElement.clientWidth) / (document.documentElement.clientHeight));
}
window.addEventListener('scroll', function (e) {
for (let i = 0; i < elements.length; i++) {
if (isInViewport(elements[i])) { //check that the element is on the screen
let y = elements[i].getBoundingClientRect().y;
elements[i].style.right = ms[i] * (y - document.body.scrollTop) +"px";
}
}
});
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}

How can I eliminate the small extra column on the right and the extra row on the bottom of my html table

I have a csv file that I load into an 11 column html table. The data displays as expected except there is a very narrow column on the far right. There is also an extra blank row at the bottom. I have made dozens of adjustments to the width percentages but the little column on the right prevails. I haven't tried to eliminate the extra row on the bottom because I don't know what to try. See CSS code.
<title>CSV to HTML5</title>
<style type="text/css">
table {
width: 850px;
display: block;
margin-left: auto;
margin-right: auto;
border: 1px solid black;
border-collapse: collapse;
}
th {
text-align: center;
padding: 6px;
border: 1px solid black;
border-collapse: collapse;
}
tr {
height: 24px;
border: 1px solid black;
}
tr:nth-child(even) {
background-color: #00FFFF;
}
td {
font-family: Arial, Verdana;
font-size: 0.8em;
font-weight: 700;
}
td {
border: 1px solid black;
cellpadding: 3px;
}
td:nth-child(1) {
width: 4%;
text-align: center;
}
td:nth-child(2) {
width: 6%;
text-align: left;
padding-left: 5px;
}
td:nth-child(3) {
width: 14%;
text-align: left;
padding-left: 5px;
}
td:nth-child(4) {
width: 14%;
text-align: left;
padding-left: 5px;
}
td:nth-child(5) {
width: 18%;
text-align: left;
padding-left: 5px;
}
td:nth-child(6) {
width: 6%;
padding-left: 5px;
}
td:nth-child(7) {
width: 5%;
text-align: center;
}
td:nth-child(8) {
width:8%;
text-align: center;
}
td:nth-child(9) {
width: 8%;
text-align: center;
}
td:nth-child(10) {
width: 8%;
text-align: center;
}
td:nth-child(11) {
width:8%;
text-align: center;
</style>
</head>
<body>
<div>
<div>
<legend>
<h1 id="clubname" style="text-align:center"></h1>
<h2 id="racename" style="text-align:center"></h2>
<h3 id="racedate" style="text-align:center"></h3>
</legend>
</div>
<div id="output">
</div>
<div id="myDiv" class="container">
<hr>
<form>
<div class="form-group">
<input type="text" class="form-control" id="inp_clubname" placeholder="Club Name" size="24" required>
<input type="text" class="form-control" id="inp_racename" placeholder="Race Name" size="24" required>
<input type="date" class="form-control" id="inp_racedate" placeholder="Date Name" size="24" required>
<label for="csvFileInput">CSV File: </label>
<input type="file" id="csvFileInput" onchange=accept=".csv" size="35" required>
<input type="button" class="btn btn-primary" onclick="generate()" value="Generate" />
</div>
</form>
<hr>
</div>
</div>
<footer>
<p style="text-align:center">©: Klexy Soft</p>
</footer>
<script type="text/javascript">
function generate() {
console.log('generate called')
//copy text from form to headings
ids = ["clubname", "racename", "racedate"]
for (i in ids) {
value = document.getElementById('inp_' + ids[i]).value
document.getElementById(ids[i]).innerHTML = value
}
files = document.getElementById('csvFileInput').files
// Check for the various File API support.
if (window.FileReader) {
// FileReader are supported.
var reader = new FileReader();
// Read file into memory as UTF-8
reader.readAsText(files[0]);
// Handle errors load
reader.onload = loadHandler;
reader.onerror = errorHandler;
} else {
alert('FileReader is not supported in this browser.');
}
}
function loadHandler(event) {
var csv = event.target.result;
processData(csv);
}
function processData(csv) {
var allTextLines = csv.split(/\r\n|\n/);
var lines = [];
for (var i = 0; i < allTextLines.length; i++) {
var data = allTextLines[i].split(',');
lines.push(data);
}
//console.log(lines);
drawOutput(lines);
}
function errorHandler(evt) {
if (evt.target.error.name == "NotReadableError") {
alert("Canno't read file !");
}
}
function drawOutput(lines) {
//Clear previous data
document.getElementById("output").innerHTML = "";
var table = document.createElement("table");
for (var i = 0; i < lines.length; i++) {
var row = document.createElement("TR");
table.appendChild(row)
for (var j = 0; j < lines[i].length; j++) {
// first row is header
cell = document.createElement(i == 0 ? "TH" : "TD");
row.appendChild(cell)
cell.appendChild(document.createTextNode(lines[i][j]));
}
}
document.getElementById("output").appendChild(table);
document.getElementById("myDiv").style.visibility = "hidden";
}
console.log('initialized')
</script>
</body>
csv file
PL,Sail#,Yacht,Type,Skipper,Club,Rtg,Finish,Elapsed,Cor'ted, 1st +,
1,1234,Boat Name,42MkII,Name,GYC,115,14:10:53,02:00:53,01:46:42,00:00:00,
2,1234,Boat Name,4000,Name,GYC,107,14:16:29,02:06:29,01:53:17,00:06:35,
3,1234,Boat Name,Catalina36MKII,Name,GYC,144,14:26:34,02:16:34,01:58:48,00:12:06,
4,1234,Boat Name,42,Name,GYC,131,14:26:37,02:16:37,02:00:28,00:13:46,
5,1234,Boat Name,Mark3,Name,GYC,218,14:52:01,02:42:01,02:15:08,00:28:26,
6,1234,Boat Name,Nonsuch 30C,Name,GYC,156,14:54:43,02:44:43,02:25:29,00:38:47,
7,1234,Boat Name,KP44,Name,GYC,168,15:25:50,03:15:50,02:55:07,01:08:25,
One of the problems I was having was the java script, function drawOutput(lines) { and the codes that perform the function, generates the table and adds an extra blank row at the bottom, I guess waiting for another line of data. By adding one more line to the java script function code, the very last line, I was able to remove the extra empty row.
document.getElementById("output").appendChild(table).deleteRow(-1);

How to Create Multiple Cursors in a single Range Slider? [duplicate]

Is it possible to make a HTML5 slider with two input values, for example to select a price range? If so, how can it be done?
I've been looking for a lightweight, dependency free dual slider for some time (it seemed crazy to import jQuery just for this) and there don't seem to be many out there. I ended up modifying #Wildhoney's code a bit and really like it.
function getVals(){
// Get slider values
var parent = this.parentNode;
var slides = parent.getElementsByTagName("input");
var slide1 = parseFloat( slides[0].value );
var slide2 = parseFloat( slides[1].value );
// Neither slider will clip the other, so make sure we determine which is larger
if( slide1 > slide2 ){ var tmp = slide2; slide2 = slide1; slide1 = tmp; }
var displayElement = parent.getElementsByClassName("rangeValues")[0];
displayElement.innerHTML = slide1 + " - " + slide2;
}
window.onload = function(){
// Initialize Sliders
var sliderSections = document.getElementsByClassName("range-slider");
for( var x = 0; x < sliderSections.length; x++ ){
var sliders = sliderSections[x].getElementsByTagName("input");
for( var y = 0; y < sliders.length; y++ ){
if( sliders[y].type ==="range" ){
sliders[y].oninput = getVals;
// Manually trigger event first time to display values
sliders[y].oninput();
}
}
}
}
section.range-slider {
position: relative;
width: 200px;
height: 35px;
text-align: center;
}
section.range-slider input {
pointer-events: none;
position: absolute;
overflow: hidden;
left: 0;
top: 15px;
width: 200px;
outline: none;
height: 18px;
margin: 0;
padding: 0;
}
section.range-slider input::-webkit-slider-thumb {
pointer-events: all;
position: relative;
z-index: 1;
outline: 0;
}
section.range-slider input::-moz-range-thumb {
pointer-events: all;
position: relative;
z-index: 10;
-moz-appearance: none;
width: 9px;
}
section.range-slider input::-moz-range-track {
position: relative;
z-index: -1;
background-color: rgba(0, 0, 0, 1);
border: 0;
}
section.range-slider input:last-of-type::-moz-range-track {
-moz-appearance: none;
background: none transparent;
border: 0;
}
section.range-slider input[type=range]::-moz-focus-outer {
border: 0;
}
<!-- This block can be reused as many times as needed -->
<section class="range-slider">
<span class="rangeValues"></span>
<input value="5" min="0" max="15" step="0.5" type="range">
<input value="10" min="0" max="15" step="0.5" type="range">
</section>
No, the HTML5 range input only accepts one input. I would recommend you to use something like the jQuery UI range slider for that task.
Coming late, but noUiSlider avoids having a jQuery-ui dependency, which the accepted answer does not. Its only "caveat" is IE support is for IE9 and newer, if legacy IE is a deal breaker for you.
It's also free, open source and can be used in commercial projects without restrictions.
Installation: Download noUiSlider, extract the CSS and JS file somewhere in your site file system, and then link to the CSS from head and to JS from body:
<!-- In <head> -->
<link href="nouislider.min.css" rel="stylesheet">
<!-- In <body> -->
<script src="nouislider.min.js"></script>
Example usage: Creates a slider which goes from 0 to 100, and starts set to 20-80.
HTML:
<div id="slider">
</div>
JS:
var slider = document.getElementById('slider');
noUiSlider.create(slider, {
start: [20, 80],
connect: true,
range: {
'min': 0,
'max': 100
}
});
Sure you can simply use two sliders overlaying each other and add a bit of javascript (actually not more than 5 lines) that the selectors are not exceeding the min/max values (like in #Garys) solution.
Attached you'll find a short snippet adapted from a current project including some CSS3 styling to show what you can do (webkit only). I also added some labels to display the selected values.
It uses JQuery but a vanillajs version is no magic though.
#Update: The code below was just a proof of concept. Due to many requests I've added a possible solution for Mozilla Firefox (without changing the original code). You may want to refractor the code below before using it.
(function() {
function addSeparator(nStr) {
nStr += '';
var x = nStr.split('.');
var x1 = x[0];
var x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + '.' + '$2');
}
return x1 + x2;
}
function rangeInputChangeEventHandler(e){
var rangeGroup = $(this).attr('name'),
minBtn = $(this).parent().children('.min'),
maxBtn = $(this).parent().children('.max'),
range_min = $(this).parent().children('.range_min'),
range_max = $(this).parent().children('.range_max'),
minVal = parseInt($(minBtn).val()),
maxVal = parseInt($(maxBtn).val()),
origin = $(this).context.className;
if(origin === 'min' && minVal > maxVal-5){
$(minBtn).val(maxVal-5);
}
var minVal = parseInt($(minBtn).val());
$(range_min).html(addSeparator(minVal*1000) + ' €');
if(origin === 'max' && maxVal-5 < minVal){
$(maxBtn).val(5+ minVal);
}
var maxVal = parseInt($(maxBtn).val());
$(range_max).html(addSeparator(maxVal*1000) + ' €');
}
$('input[type="range"]').on( 'input', rangeInputChangeEventHandler);
})();
body{
font-family: sans-serif;
font-size:14px;
}
input[type='range'] {
width: 210px;
height: 30px;
overflow: hidden;
cursor: pointer;
outline: none;
}
input[type='range'],
input[type='range']::-webkit-slider-runnable-track,
input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
background: none;
}
input[type='range']::-webkit-slider-runnable-track {
width: 200px;
height: 1px;
background: #003D7C;
}
input[type='range']:nth-child(2)::-webkit-slider-runnable-track{
background: none;
}
input[type='range']::-webkit-slider-thumb {
position: relative;
height: 15px;
width: 15px;
margin-top: -7px;
background: #fff;
border: 1px solid #003D7C;
border-radius: 25px;
z-index: 1;
}
input[type='range']:nth-child(1)::-webkit-slider-thumb{
z-index: 2;
}
.rangeslider{
position: relative;
height: 60px;
width: 210px;
display: inline-block;
margin-top: -5px;
margin-left: 20px;
}
.rangeslider input{
position: absolute;
}
.rangeslider{
position: absolute;
}
.rangeslider span{
position: absolute;
margin-top: 30px;
left: 0;
}
.rangeslider .right{
position: relative;
float: right;
margin-right: -5px;
}
/* Proof of concept for Firefox */
#-moz-document url-prefix() {
.rangeslider::before{
content:'';
width:100%;
height:2px;
background: #003D7C;
display:block;
position: relative;
top:16px;
}
input[type='range']:nth-child(1){
position:absolute;
top:35px !important;
overflow:visible !important;
height:0;
}
input[type='range']:nth-child(2){
position:absolute;
top:35px !important;
overflow:visible !important;
height:0;
}
input[type='range']::-moz-range-thumb {
position: relative;
height: 15px;
width: 15px;
margin-top: -7px;
background: #fff;
border: 1px solid #003D7C;
border-radius: 25px;
z-index: 1;
}
input[type='range']:nth-child(1)::-moz-range-thumb {
transform: translateY(-20px);
}
input[type='range']:nth-child(2)::-moz-range-thumb {
transform: translateY(-20px);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div class="rangeslider">
<input class="min" name="range_1" type="range" min="1" max="100" value="10" />
<input class="max" name="range_1" type="range" min="1" max="100" value="90" />
<span class="range_min light left">10.000 €</span>
<span class="range_max light right">90.000 €</span>
</div>
Actually I used my script in html directly. But in javascript when you add oninput event listener for this event it gives the data automatically.You just need to assign the value as per your requirement.
[slider] {
width: 300px;
position: relative;
height: 5px;
margin: 45px 0 10px 0;
}
[slider] > div {
position: absolute;
left: 13px;
right: 15px;
height: 5px;
}
[slider] > div > [inverse-left] {
position: absolute;
left: 0;
height: 5px;
border-radius: 10px;
background-color: #CCC;
margin: 0 7px;
}
[slider] > div > [inverse-right] {
position: absolute;
right: 0;
height: 5px;
border-radius: 10px;
background-color: #CCC;
margin: 0 7px;
}
[slider] > div > [range] {
position: absolute;
left: 0;
height: 5px;
border-radius: 14px;
background-color: #d02128;
}
[slider] > div > [thumb] {
position: absolute;
top: -7px;
z-index: 2;
height: 20px;
width: 20px;
text-align: left;
margin-left: -11px;
cursor: pointer;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
background-color: #FFF;
border-radius: 50%;
outline: none;
}
[slider] > input[type=range] {
position: absolute;
pointer-events: none;
-webkit-appearance: none;
z-index: 3;
height: 14px;
top: -2px;
width: 100%;
opacity: 0;
}
div[slider] > input[type=range]:focus::-webkit-slider-runnable-track {
background: transparent;
border: transparent;
}
div[slider] > input[type=range]:focus {
outline: none;
}
div[slider] > input[type=range]::-webkit-slider-thumb {
pointer-events: all;
width: 28px;
height: 28px;
border-radius: 0px;
border: 0 none;
background: red;
-webkit-appearance: none;
}
div[slider] > input[type=range]::-ms-fill-lower {
background: transparent;
border: 0 none;
}
div[slider] > input[type=range]::-ms-fill-upper {
background: transparent;
border: 0 none;
}
div[slider] > input[type=range]::-ms-tooltip {
display: none;
}
[slider] > div > [sign] {
opacity: 0;
position: absolute;
margin-left: -11px;
top: -39px;
z-index:3;
background-color: #d02128;
color: #fff;
width: 28px;
height: 28px;
border-radius: 28px;
-webkit-border-radius: 28px;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
text-align: center;
}
[slider] > div > [sign]:after {
position: absolute;
content: '';
left: 0;
border-radius: 16px;
top: 19px;
border-left: 14px solid transparent;
border-right: 14px solid transparent;
border-top-width: 16px;
border-top-style: solid;
border-top-color: #d02128;
}
[slider] > div > [sign] > span {
font-size: 12px;
font-weight: 700;
line-height: 28px;
}
[slider]:hover > div > [sign] {
opacity: 1;
}
<div slider id="slider-distance">
<div>
<div inverse-left style="width:70%;"></div>
<div inverse-right style="width:70%;"></div>
<div range style="left:0%;right:0%;"></div>
<span thumb style="left:0%;"></span>
<span thumb style="left:100%;"></span>
<div sign style="left:0%;">
<span id="value">0</span>
</div>
<div sign style="left:100%;">
<span id="value">100</span>
</div>
</div>
<input type="range" value="0" max="100" min="0" step="1" oninput="
this.value=Math.min(this.value,this.parentNode.childNodes[5].value-1);
let value = (this.value/parseInt(this.max))*100
var children = this.parentNode.childNodes[1].childNodes;
children[1].style.width=value+'%';
children[5].style.left=value+'%';
children[7].style.left=value+'%';children[11].style.left=value+'%';
children[11].childNodes[1].innerHTML=this.value;" />
<input type="range" value="100" max="100" min="0" step="1" oninput="
this.value=Math.max(this.value,this.parentNode.childNodes[3].value-(-1));
let value = (this.value/parseInt(this.max))*100
var children = this.parentNode.childNodes[1].childNodes;
children[3].style.width=(100-value)+'%';
children[5].style.right=(100-value)+'%';
children[9].style.left=value+'%';children[13].style.left=value+'%';
children[13].childNodes[1].innerHTML=this.value;" />
</div>
The question was: "Is it possible to make a HTML5 slider with two input values, for example to select a price range? If so, how can it be done?"
In 2020 it is possible to create a fully accessible, native, non-jquery HTML5 slider with two thumbs for price ranges. If found this posted after I already created this solution and I thought that it would be nice to share my implementation here.
This implementation has been tested on mobile Chrome and Firefox (Android) and Chrome and Firefox (Linux). I am not sure about other platforms, but it should be quite good. I would love to get your feedback and improve this solution.
This solution allows multiple instances on one page and it consists of just two inputs (each) with descriptive labels for screen readers. You can set the thumb size in the amount of grid labels. Also, you can use touch, keyboard and mouse to interact with the slider. The value is updated during adjustment, due to the 'on input' event listener.
My first approach was to overlay the sliders and clip them. However, that resulted in complex code with a lot of browser dependencies. Then I recreated the solution with two sliders that were 'inline'. This is the solution you will find below.
var thumbsize = 14;
function draw(slider,splitvalue) {
/* set function vars */
var min = slider.querySelector('.min');
var max = slider.querySelector('.max');
var lower = slider.querySelector('.lower');
var upper = slider.querySelector('.upper');
var legend = slider.querySelector('.legend');
var thumbsize = parseInt(slider.getAttribute('data-thumbsize'));
var rangewidth = parseInt(slider.getAttribute('data-rangewidth'));
var rangemin = parseInt(slider.getAttribute('data-rangemin'));
var rangemax = parseInt(slider.getAttribute('data-rangemax'));
/* set min and max attributes */
min.setAttribute('max',splitvalue);
max.setAttribute('min',splitvalue);
/* set css */
min.style.width = parseInt(thumbsize + ((splitvalue - rangemin)/(rangemax - rangemin))*(rangewidth - (2*thumbsize)))+'px';
max.style.width = parseInt(thumbsize + ((rangemax - splitvalue)/(rangemax - rangemin))*(rangewidth - (2*thumbsize)))+'px';
min.style.left = '0px';
max.style.left = parseInt(min.style.width)+'px';
min.style.top = lower.offsetHeight+'px';
max.style.top = lower.offsetHeight+'px';
legend.style.marginTop = min.offsetHeight+'px';
slider.style.height = (lower.offsetHeight + min.offsetHeight + legend.offsetHeight)+'px';
/* correct for 1 off at the end */
if(max.value>(rangemax - 1)) max.setAttribute('data-value',rangemax);
/* write value and labels */
max.value = max.getAttribute('data-value');
min.value = min.getAttribute('data-value');
lower.innerHTML = min.getAttribute('data-value');
upper.innerHTML = max.getAttribute('data-value');
}
function init(slider) {
/* set function vars */
var min = slider.querySelector('.min');
var max = slider.querySelector('.max');
var rangemin = parseInt(min.getAttribute('min'));
var rangemax = parseInt(max.getAttribute('max'));
var avgvalue = (rangemin + rangemax)/2;
var legendnum = slider.getAttribute('data-legendnum');
/* set data-values */
min.setAttribute('data-value',rangemin);
max.setAttribute('data-value',rangemax);
/* set data vars */
slider.setAttribute('data-rangemin',rangemin);
slider.setAttribute('data-rangemax',rangemax);
slider.setAttribute('data-thumbsize',thumbsize);
slider.setAttribute('data-rangewidth',slider.offsetWidth);
/* write labels */
var lower = document.createElement('span');
var upper = document.createElement('span');
lower.classList.add('lower','value');
upper.classList.add('upper','value');
lower.appendChild(document.createTextNode(rangemin));
upper.appendChild(document.createTextNode(rangemax));
slider.insertBefore(lower,min.previousElementSibling);
slider.insertBefore(upper,min.previousElementSibling);
/* write legend */
var legend = document.createElement('div');
legend.classList.add('legend');
var legendvalues = [];
for (var i = 0; i < legendnum; i++) {
legendvalues[i] = document.createElement('div');
var val = Math.round(rangemin+(i/(legendnum-1))*(rangemax - rangemin));
legendvalues[i].appendChild(document.createTextNode(val));
legend.appendChild(legendvalues[i]);
}
slider.appendChild(legend);
/* draw */
draw(slider,avgvalue);
/* events */
min.addEventListener("input", function() {update(min);});
max.addEventListener("input", function() {update(max);});
}
function update(el){
/* set function vars */
var slider = el.parentElement;
var min = slider.querySelector('#min');
var max = slider.querySelector('#max');
var minvalue = Math.floor(min.value);
var maxvalue = Math.floor(max.value);
/* set inactive values before draw */
min.setAttribute('data-value',minvalue);
max.setAttribute('data-value',maxvalue);
var avgvalue = (minvalue + maxvalue)/2;
/* draw */
draw(slider,avgvalue);
}
var sliders = document.querySelectorAll('.min-max-slider');
sliders.forEach( function(slider) {
init(slider);
});
* {padding: 0; margin: 0;}
body {padding: 40px;}
.min-max-slider {position: relative; width: 200px; text-align: center; margin-bottom: 50px;}
.min-max-slider > label {display: none;}
span.value {height: 1.7em; font-weight: bold; display: inline-block;}
span.value.lower::before {content: "€"; display: inline-block;}
span.value.upper::before {content: "- €"; display: inline-block; margin-left: 0.4em;}
.min-max-slider > .legend {display: flex; justify-content: space-between;}
.min-max-slider > .legend > * {font-size: small; opacity: 0.25;}
.min-max-slider > input {cursor: pointer; position: absolute;}
/* webkit specific styling */
.min-max-slider > input {
-webkit-appearance: none;
outline: none!important;
background: transparent;
background-image: linear-gradient(to bottom, transparent 0%, transparent 30%, silver 30%, silver 60%, transparent 60%, transparent 100%);
}
.min-max-slider > input::-webkit-slider-thumb {
-webkit-appearance: none; /* Override default look */
appearance: none;
width: 14px; /* Set a specific slider handle width */
height: 14px; /* Slider handle height */
background: #eee; /* Green background */
cursor: pointer; /* Cursor on hover */
border: 1px solid gray;
border-radius: 100%;
}
.min-max-slider > input::-webkit-slider-runnable-track {cursor: pointer;}
<div class="min-max-slider" data-legendnum="2">
<label for="min">Minimum price</label>
<input id="min" class="min" name="min" type="range" step="1" min="0" max="3000" />
<label for="max">Maximum price</label>
<input id="max" class="max" name="max" type="range" step="1" min="0" max="3000" />
</div>
Note that you should keep the step size to 1 to prevent the values to change due to redraws/redraw bugs.
View online at: https://codepen.io/joosts/pen/rNLdxvK
2022 - Accessible solution - 30 second solution to implement
This solution builds off of this answer by #JoostS. Accessibility is something none of the answers have focused on and that is a problem, so I built off of the above answer by making it more accessible & extensible since it had some flaws.
Usage is very simple:
Use the CDN or host the script locally: https://cdn.jsdelivr.net/gh/maxshuty/accessible-web-components/dist/simpleRange.min.js
Add this element to your template or HTML: <range-selector min-range="0" max-range="1000" />
Hook into it by listening for the range-changed event (or whatever event-name-to-emit-on-change you pass in)
That's it. View the full demo here. You can easily customize it by simply applying attributes like inputs-for-labels to use inputs instead of labels, slider-color to adjust the color, and so much more!
Here is a fiddle:
window.addEventListener('range-changed', (e) => {console.log(`Range changed for: ${e.detail.sliderId}. Min/Max range values are available in this object too`)})
<script src="https://cdn.jsdelivr.net/gh/maxshuty/accessible-web-components#latest/dist/simpleRange.min.js"></script>
<div>
<range-selector
id="rangeSelector1"
min-label="Minimum"
max-label="Maximum"
min-range="1000"
max-range="2022"
number-of-legend-items-to-show="6"
/>
</div>
<div>
<range-selector
id="rangeSelector1"
min-label="Minimum"
max-label="Maximum"
min-range="1"
max-range="500"
number-of-legend-items-to-show="3"
inputs-for-labels
/>
</div>
<div>
<range-selector
id="rangeSelector2"
min-label="Minimum"
max-label="Maximum"
min-range="1000"
max-range="2022"
number-of-legend-items-to-show="3"
slider-color="#6b5b95"
/>
</div>
<div>
<range-selector
id="rangeSelector3"
min-label="Minimum"
max-label="Maximum"
min-range="1000"
max-range="2022"
hide-label
hide-legend
/>
</div>
I decided to address the issues of the linked answer like the labels using display: none (bad for a11y), no visual focus on the slider, etc., and improve the code by cleaning up event listeners and making it much more dynamic and extensible.
I created this tiny library with many options to customize colors, event names, easily hook into it, make the accessible labels i18n capable and much more. Here it is in a fiddle if you want to play around.
You can easily customize the number of legend items it shows, hide or show the labels and legend, and customize the colors of everything, including the focus color like this.
Example using several of the props:
<range-selector
min-label="i18n Minimum Range"
max-label="i18n Maximum Range"
min-range="5"
max-range="555"
number-of-legend-items-to-show="6"
event-name-to-emit-on-change="my-custom-range-changed-event"
slider-color="orange"
circle-color="#f7cac9"
circle-border-color="#083535"
circle-focus-border-color="#3ec400"
/>
Then in your script:
window.addEventListener('my-custom-range-changed-event', (e) => { const data = e.detail; });
Finally if you see that this is missing something that you need I made it very easy to customize this library.
Simply copy this file and at the top you can see cssHelpers and constants objects that contain most of the variables you would likely want to further customize.
Since I built this with a Native Web Component I have taken advantage of disconnectedCallback and other hooks to clean up event listeners and set things up.
Here is a reusable double range slider implementation, base on tutorial Double Range Slider by Coding Artist
near native UI, Chrome/Firefox/Safari compatible
API EventTarget based, with change/input events, minGap/maxGap properties
let $ = (s, c = document) => c.querySelector(s);
let $$ = (s, c = document) => Array.prototype.slice.call(c.querySelectorAll(s));
class DoubleRangeSlider extends EventTarget {
#minGap = 0;
#maxGap = Number.MAX_SAFE_INTEGER;
#inputs;
style = {
trackColor: '#dadae5',
rangeColor: '#3264fe',
};
constructor(container){
super();
let inputs = $$('input[type="range"]', container);
if(inputs.length !== 2){
throw new RangeError('2 range inputs expected');
}
let [input1, input2] = inputs;
if(input1.min >= input1.max || input2.min >= input2.max){
throw new RangeError('range min should be less than max');
}
if(input1.max > input2.max || input1.min > input2.min){
throw new RangeError('input1\'s max/min should not be greater than input2\'s max/min');
}
this.#inputs = inputs;
let sliderTrack = $('.slider-track', container);
let lastValue1 = input1.value;
input1.addEventListener('input', (e) => {
let value1 = +input1.value;
let value2 = +input2.value;
let minGap = this.#minGap;
let maxGap = this.#maxGap;
let gap = value2 - value1;
let newValue1 = value1;
if(gap < minGap){
newValue1 = value2 - minGap;
}else if(gap > maxGap){
newValue1 = value2 - maxGap;
}
input1.value = newValue1;
if(input1.value !== lastValue1){
lastValue1 = input1.value;
passEvent(e);
fillColor();
}
});
let lastValue2 = input2.value;
input2.addEventListener('input', (e) => {
let value1 = +input1.value;
let value2 = +input2.value;
let minGap = this.#minGap;
let maxGap = this.#maxGap;
let gap = value2 - value1;
let newValue2 = value2;
if(gap < minGap){
newValue2 = value1 + minGap;
}else if(gap > maxGap){
newValue2 = value1 + maxGap;
}
input2.value = newValue2;
if(input2.value !== lastValue2){
lastValue2 = input2.value;
passEvent(e);
fillColor();
}
});
let passEvent = (e) => {
this.dispatchEvent(new e.constructor(e.type, e));
};
input1.addEventListener('change', passEvent);
input2.addEventListener('change', passEvent);
let fillColor = () => {
let overallMax = +input2.max;
let overallMin = +input1.min;
let overallRange = overallMax - overallMin;
let left1 = ((input1.value - overallMin) / overallRange * 100) + '%';
let left2 = ((input2.value - overallMin) / overallRange * 100) + '%';
let {trackColor, rangeColor} = this.style;
sliderTrack.style.background = `linear-gradient(to right, ${trackColor} ${left1}, ${rangeColor} ${left1}, ${rangeColor} ${left2}, ${trackColor} ${left2})`;
};
let init = () => {
let overallMax = +input2.max;
let overallMin = +input1.min;
let overallRange = overallMax - overallMin;
let range1 = input1.max - overallMin;
let range2 = overallMax - input2.min;
input1.style.left = '0px';
input1.style.width = (range1 / overallRange * 100) + '%';
input2.style.right = '0px';
input2.style.width = (range2 / overallRange * 100) + '%';
fillColor();
};
init();
}
get minGap(){
return this.#minGap;
}
set minGap(v){
this.#minGap = v;
}
get maxGap(){
return this.#maxGap;
}
set maxGap(v){
this.#maxGap = v;
}
get values(){
return this.#inputs.map((el) => el.value);
}
set values(values){
if(values.length !== 2 || !values.every(isFinite))
throw new RangeError();
let [input1, input2] = this.#inputs;
let [value1, value2] = values;
if(value1 > input1.max || value1 < input1.min)
throw new RangeError('invalid value for input1');
if(value2 > input2.max || value2 < input2.min)
throw new RangeError('invalid value for input2');
input1.value = value1;
input2.value = value2;
}
get inputs(){
return this.#inputs;
}
get overallMin(){
return this.#inputs[0].min;
}
get overallMax(){
return this.#inputs[1].max;
}
}
function main(){
let container = $('.slider-container');
let slider = new DoubleRangeSlider(container);
slider.minGap = 30;
slider.maxGap = 70;
let inputs = $$('input[name="a"]');
let outputs = $$('output[name="a"]');
outputs[0].value = inputs[0].value;
outputs[1].value = inputs[1].value;
slider.addEventListener('input', (e) => {
let values = slider.values;
outputs[0].value = values[0];
outputs[1].value = values[1];
});
slider.addEventListener('change', (e) => {
let values = slider.values;
console.log('change', values);
outputs[0].value = values[0];
outputs[1].value = values[1];
});
}
document.addEventListener('DOMContentLoaded', main);
.slider-container {
display: inline-block;
position: relative;
width: 360px;
height: 28px;
}
.slider-track {
width: 100%;
height: 5px;
position: absolute;
margin: auto;
top: 0;
bottom: 0;
border-radius: 5px;
}
.slider-container>input[type="range"] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
position: absolute;
margin: auto;
top: 0;
bottom: 0;
width: 100%;
outline: none;
background-color: transparent;
pointer-events: none;
}
.slider-container>input[type="range"]::-webkit-slider-runnable-track {
-webkit-appearance: none;
height: 5px;
}
.slider-container>input[type="range"]::-moz-range-track {
-moz-appearance: none;
height: 5px;
}
.slider-container>input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
margin-top: -9px;
height: 1.7em;
width: 1.7em;
background-color: #3264fe;
cursor: pointer;
pointer-events: auto;
border-radius: 50%;
}
.slider-container>input[type="range"]::-moz-range-thumb {
-moz-appearance: none;
height: 1.7em;
width: 1.7em;
cursor: pointer;
border: none;
border-radius: 50%;
background-color: #3264fe;
pointer-events: auto;
}
.slider-container>input[type="range"]:active::-webkit-slider-thumb {
background-color: #ffffff;
border: 3px solid #3264fe;
}
<h3>Double Range Slider, Reusable Edition</h3>
<div class="slider-container">
<div class="slider-track"></div>
<input type="range" name="a" min="-130" max="-30" step="1" value="-100" autocomplete="off" />
<input type="range" name="a" min="-60" max="0" step="2" value="-30" autocomplete="off" />
</div>
<div>
<output name="a"></output> ~ <output name="a"></output>
</div>
<pre>
Changes:
1. allow different min/max/step for two inputs
2. new property 'maxGap'
3. added events 'input'/'change'
4. dropped IE/OldEdge support
</pre>
For those working with Vue, there is now Veeno available, based on noUiSlider. But it does not seem to be maintained anymore. :-(
This code covers following points
Dual slider using HTML, CSS, JS
I have modified this slider using embedded ruby so we can save previously applied values using params in rails.
<% left_width = params[:min].nil? ? 0 : ((params[:min].to_f/100000) * 100).to_i %>
<% left_value = params[:min].nil? ? '0' : params[:min] %>
<% right_width = params[:max].nil? ? 100 : ((params[:max].to_f/100000) * 100).to_i %>
<% right_value = params[:max].nil? ? '100000' : params[:max] %>
<div class="range-slider-outer">
<div slider id="slider-distance">
<div class="slider-inner">
<div inverse-left style="width:<%= left_width %>%;"></div>
<div inverse-right style="width:<%= 100 - right_width %>%;"></div>
<div range style="left:<%= left_width %>%;right:<%= 100 - right_width %>%;"></div>
<span thumb style="left:<%= left_width %>%;"></span>
<span thumb style="left:<%= right_width %>%;"></span>
<div sign style="">
Rs.<span id="value"><%= left_value.to_i %></span> to
</div>
<div sign style="">
Rs.<span id="value"><%= right_value.to_i %></span>
</div>
</div>
<input type="range" name="min" value=<%= left_value %> max="100000" min="0" step="100" oninput="
this.value=Math.min(this.value,this.parentNode.childNodes[5].value-1);
let value = (this.value/parseInt(this.max))*100
var children = this.parentNode.childNodes[1].childNodes;
children[1].style.width=value+'%';
children[5].style.left=value+'%';
children[7].style.left=value+'%';children[11].style.left=value+'%';
children[11].childNodes[1].innerHTML=this.value;" />
<input type="range" name="max" value=<%= right_value %> max="100000" min="0" step="100" oninput="
this.value=Math.max(this.value,this.parentNode.childNodes[3].value-(-1));
let value = (this.value/parseInt(this.max))*100
var children = this.parentNode.childNodes[1].childNodes;
children[3].style.width=(100-value)+'%';
children[5].style.right=(100-value)+'%';
children[9].style.left=value+'%';children[13].style.left=value+'%';
children[13].childNodes[1].innerHTML=this.value;" />
</div>
<div class="range-label">
<div>0</div>
<div>100000</div>
</div>
</div>
[slider] {
/*width: 300px;*/
position: relative;
height: 5px;
/*margin: 20px auto;*/
/* height: 100%; */
}
[slider] > div {
position: absolute;
left: 13px;
right: 15px;
height: 14px;
top: 5px;
}
[slider] > div > [inverse-left] {
position: absolute;
left: 0;
height: 14px;
border-radius: 3px;
background-color: #CCC;
/*margin: 0 7px;*/
margin: 0 -7px;
}
[slider] > div > [inverse-right] {
position: absolute;
right: 0;
height: 14px;
border-radius: 3px;
background-color: #CCC;
/*margin: 0 7px;*/
margin: 0 -7px;
}
[slider] > div > [range] {
position: absolute;
left: 0;
height: 14px;
border-radius: 14px;
background-color:#8950fc;
}
[slider] > div > [thumb] {
position: absolute;
top: -3px;
z-index: 2;
height: 20px;
width: 20px;
text-align: left;
margin-left: -11px;
cursor: pointer;
/* box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4); */
background-color: #FFF;
/*border-radius: 50%;*/
border-radius:2px;
outline: none;
}
[slider] > input[type=range] {
position: absolute;
pointer-events: none;
-webkit-appearance: none;
z-index: 3;
height: 14px;
top: -2px;
width: 100%;
opacity: 0;
}
div[slider] > input[type=range]:focus::-webkit-slider-runnable-track {
background: transparent;
border: transparent;
}
div[slider] > input[type=range]:focus {
outline: none;
}
div[slider] > input[type=range]::-webkit-slider-thumb {
pointer-events: all;
width: 28px;
height: 28px;
border-radius: 0px;
border: 0 none;
background: red;
-webkit-appearance: none;
}
div[slider] > input[type=range]::-ms-fill-lower {
background: transparent;
border: 0 none;
}
div[slider] > input[type=range]::-ms-fill-upper {
background: transparent;
border: 0 none;
}
div[slider] > input[type=range]::-ms-tooltip {
display: none;
}
[slider] > div > [sign] {
/* opacity: 0;
position: absolute;
margin-left: -11px;
top: -39px;
z-index:3;
background-color:#1a243a;
color: #fff;
width: 28px;
height: 28px;
border-radius: 28px;
-webkit-border-radius: 28px;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
text-align: center;*/
color: #A5B2CB;
border-radius: 28px;
justify-content: center;
text-align: center;
display: inline-block;
margin-top: 12px;
font-size: 14px;
font-weight: bold;
}
.slider-inner{
text-align:center;
}
/*[slider] > div > [sign]:after {
position: absolute;
content: '';
left: 0;
border-radius: 16px;
top: 19px;
border-left: 14px solid transparent;
border-right: 14px solid transparent;
border-top-width: 16px;
border-top-style: solid;
border-top-color:#1a243a;
}*/
[slider] > div > [sign] > span {
font-size: 12px;
font-weight: 700;
line-height: 28px;
}
[slider]:hover > div > [sign] {
opacity: 1;
}
.range-label{
display: flex;
justify-content: space-between;
margin-top: 28px;
padding: 0px 5px;
}
.range-slider-outer{
width:calc(100% - 20px);
margin:auto;
margin-bottom: 10px;
margin-top: 10px;
}

Process Line layout issue

I am trying to build one page from my layout but I have some hard time. I have to create a Process line as shown on the picture. I am trying also to make it responsive but i have the feeling that my code is very messy.
.process-steps h2 { font-family: "Rubik-Regular", sans-serif; font-size: 40px; color: #1e1e22; margin: 55px 0 70px 0; }
.process-steps .green-span { font-family: "Rubik-Bold", sans-serif; color: #23b58a; }
.actual-graph { position: relative; display: flex; justify-content: center; align-items: center; }
.actual-graph h4 { font-family: "Rubik-Medium", sans-serif; font-size: 18px; color: #2a2a2e; line-height: 28px; }
.actual-graph p { font-family: "Rubik-Regular", sans-serif; font-size: 16px; color: #46464c; line-height: 22px; }
.step-1 { position: absolute; width: 25%; right: 86%; bottom: 0; left: 0; top: 42%; }
.step-2 { position: absolute; width: 25%; left: 13%; bottom: 0; right: 0; top: -7.8%; }
.step-3 { position: absolute; width: 25%; left: 37.5%; bottom: 0; right: 0; top: 42%; }
.step-4 { position: absolute; width: 25%; left: 61%; bottom: 0; right: 0; top: -7.8%; }
.step-5 { position: absolute; width: 25%; left: 85%; bottom: 0; right: 0; top: 42%; }
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<section class="process-steps">
<div class="container">
<h2><span class="green-span">5 Steps</span> Process</h2>
<div class="graph-container">
<div class="actual-graph">
<img src="https://s17.postimg.org/bhxksjwkf/graph.png" width="1171" height="191" title="someText" alt="someText" class="img-responsive">
<div class="step-1">
<h4>Create your account</h4>
<p>The process begins when you
<br>create an account with Sellr.</p>
</div>
<!-- step-1 -->
<div class="step-2">
<h4>Select Store Picks</h4>
<p>Select 20-30 products from
<br>each product category that you
<br>want to promote.</p>
</div>
<div class="step-3">
<h4>Wait for processing</h4>
<p>We ensure high quality
<br>information on your store picks
<br>in 7-10 business days.</p>
</div>
<div class="step-4">
<h4>Install Sellr Tablets</h4>
<p>Place Sellr tablets throughout
<br>your store.</p>
</div>
<div class="step-5">
<h4>Start increasing sales!</h4>
<p>Your store is now equipped to
<br>start increasing sales for your
<br>selected products.</p>
</div>
</div>
</div>
</div>
<!-- container -->
</section>
<!-- process-steps -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
[https://codepen.io/sheetalsinghwd/pen/LYYMOam]
var canvas, ctx, p = function (x,y) {
return { x:x, y:y };
};
// drawing
$(function() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext('2d');
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.lineCap = 'round';
ctx.lineWidth = 4;
ctx.strokeStyle = 'rgba(50,30,120,0.5)';
ctx.beginPath();
ctx.wavy(p(80, 120), p(650, 120), 2, 12, 4);
ctx.stroke();
});
CanvasRenderingContext2D.prototype.wavy = function(from, to, frequency, amplitude, step, negative)
{
var cx = 0, cy = 0,
fx = from.x, fy = from.y,
tx = to.x, ty = to.y,
i = 0, waveOffsetLength = 0,
ang = Math.atan2(ty - fy, tx - fx),
distance = Math.sqrt((fx - tx) * (fx - tx) + (fy - ty) * (fy - ty)),
a = amplitude * (!negative ? 1 : -1),
f = Math.PI * frequency;
for (i; i <= distance; i += step)
{
waveOffsetLength = Math.sin((i / distance) * f) * a;
cx = from.x + Math.cos(ang) * i + Math.cos(ang - Math.PI/2) * waveOffsetLength;
cy = from.y + Math.sin(ang) * i + Math.sin(ang - Math.PI/2) * waveOffsetLength;
i > 0 ? this.lineTo(cx, cy) : this.moveTo(cx, cy);
}
}
use this for canvas
you can refer to this link.. even i am working on that.. i have just tried to create wavy lines through css and javascript`

Iframe 100% height inside body with padding

I have an iframe in my HTML document and I'm having a bit of trouble.
I also have a URL bar (fixed position element) at the top of the page that should stay with the user as they scroll. That works fine. I'd like the iframe to fill the remaining space but not be covered up by the URL bar.
This is what I'm talking about. http://s75582.gridserver.com/Ls
How can I fix this so that the URL bar doesn't cover up part of the page? When I try setting padding in the body, it just creates an extra, annoying scroll bar.
Whilst you can't say ‘height: 100% minus some pixels’ in CSS, you can make the iframe 100% high, then push its top down using padding. Then you can take advantage of the CSS3 box-sizing property to make the padding get subtracted from the height.
This:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head>
<title>test</title>
<style type="text/css">
html, body { margin: 0; padding: 0; height: 100%; }
#bar { height: 32px; background: red; }
iframe {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
border: none; padding-top: 32px;
box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box;
}
</style>
</head><body>
<iframe src="http://www.google.com/"></iframe>
<div id="bar">foo</div>
<body></html>
Works on IE8, Moz, Op, Saf, Chrome. You'd have to carry on using a JavaScript fallback to make the extra scrollbar disappear for browsers that don't support box-sizing though (in particular IE up to 7).
It can be done without any Javascript, works in IE7
CSS:
body {
overflow-y: hidden;
}
#imagepgframe {
width: 100%;
height: 100%;
position: absolute;
}
#wrap {
width: 100%;
position: absolute;
top: 100px;
left: 0;
bottom: 0;
}
HTML:
<div id="wrap">
<iframe id="imagepgframe" frameBorder="0" src="http://en.wikipedia.org/wiki/Internet_Explorer_7"></iframe>
</div>
To build on top of bobince's answer:
Erik Arvidsson came up with a way to (kinda, sorta) add box-sizing support to IE6/IE7. However, his solution doesn't support units other than px. Like you, I needed a percentage height, so I added support for percents.
Once you've downloaded and unzipped the zip file, open boxsizing.htc and replace the following border/padding functions:
/* border width getters */
function getBorderWidth(el, sSide) {
if (el.currentStyle["border" + sSide + "Style"] == "none")
return 0;
var n = parseInt(el.currentStyle["border" + sSide + "Width"]);
return n || 0;
}
function getBorderLeftWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Left"); }
function getBorderRightWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Right"); }
function getBorderTopWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Top"); }
function getBorderBottomWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Bottom"); }
/* end border width getters */
/* padding getters */
function getPadding(el, sSide) {
var n = parseInt(el.currentStyle["padding" + sSide]);
return n || 0;
}
function getPaddingLeft() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Left"); }
function getPaddingRight() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Right"); }
function getPaddingTop() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Top"); }
function getPaddingBottom() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Bottom"); }
/* end padding getters */
Then replace updateBorderBoxWidth and updateBorderBoxHeight with the following:
function updateBorderBoxWidth() {
element.runtimeStyle.width = "";
if (getDocumentBoxSizing() == getBoxSizing())
return;
var csw = element.currentStyle.width;
var w = null;
if (csw != "auto" && csw.indexOf("px") != -1) {
w = parseInt(csw);
} else if (csw != "auto" && csw.indexOf("%") != -1) {
var origDisplay = element.runtimeStyle.display;
element.runtimeStyle.display = "none";
w = Math.max(0, (parseInt(element.parentNode.clientWidth) - (
getBorderLeftWidth(element.parentNode)
+ getPaddingLeft(element.parentNode)
+ getPaddingRight(element.parentNode)
+ getBorderRightWidth(element.parentNode)
)) * (parseInt(csw) / 100));
element.runtimeStyle.display = origDisplay;
}
if (w !== null) {
if (getBoxSizing() == "border-box") {
setBorderBoxWidth(w);
} else {
setContentBoxWidth(w);
}
}
}
function updateBorderBoxHeight() {
element.runtimeStyle.height = "";
if (getDocumentBoxSizing() == getBoxSizing())
return;
var csh = element.currentStyle.height;
var h = null;
if (csh != "auto" && csh.indexOf("px") != -1) {
h = parseInt(csh);
} else if (csh != "auto" && csh.indexOf("%") != -1) {
var origDisplay = element.runtimeStyle.display;
element.runtimeStyle.display = "none";
h = Math.max(0, (parseInt(element.parentNode.clientHeight) - (
getBorderTopWidth(element.parentNode)
+ getPaddingTop(element.parentNode)
+ getPaddingBottom(element.parentNode)
+ getBorderBottomWidth(element.parentNode)
)) * (parseInt(csh) / 100));
element.runtimeStyle.display = origDisplay;
}
if (h !== null) {
if (getBoxSizing() == "border-box") {
setBorderBoxHeight(h);
} else {
setContentBoxHeight(h);
}
}
}
Then just use the file as you would otherwise:
.border-box {
behavior: url("boxsizing.htc");
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
Here's a pretty thorough test I put together while developing my modifications:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>box-sizing: border-box;</title>
<style type="text/css">
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background: yellow;
}
body {
padding-top: 50px;
padding-bottom: 50px;
}
p {
margin: 0;
}
#header, #footer {
height: 50px;
position: absolute;
width: 100%;
overflow: hidden;
}
#header {
background: red;
top: 0;
}
#footer {
background: blue;
bottom: 0;
}
#content {
width: 100%;
height: 100%;
border: none;
margin: 0;
padding: 0;
background: black;
color: white;
overflow: auto;
position: relative;
padding-top: 40px;
padding-bottom: 40px;
}
#nested-header, #nested-footer {
position: absolute;
height: 40px;
width: 100%;
background: #CCC;
}
#nested-header {
top: 0;
}
#nested-footer {
bottom: 0;
}
#nested-content-wrap {
height: 100%;
}
#nested-floater {
height: 100%;
float: left;
width: 100px;
}
#nested-content {
height: 100%;
background: green;
color: black;
overflow: auto;
position: relative;
}
#inner-nest {
height: 100%;
position: relative;
}
#inner-head {
height: 30px;
width: 100%;
background: #AAA;
position: absolute;
top: 0;
}
#inner-content {
padding-top: 30px;
height: 100%;
overflow: auto;
}
.border-box {
behavior: url("boxsizing.htc");
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.content-box {
behavior: url("boxsizing.htc");
box-sizing: content-box;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
}
legend {
color: black;
}
form {
margin: 1em 0;
}
.wrap {
height: 100px;
background: #000;
overflow: hidden;
}
.test {
width: 100px;
height: 100%;
background: #AAA;
border-color: #EEE;
padding-left: 20px;
padding-top: 20px;
padding-bottom: 5px;
float: left;
}
.fill {
width: 100%;
height: 100%;
background: #CCC;
}
.gauge {
width: 99px;
background: white;
border-right: 1px solid green;
height: 100%;
float: left;
}
.notes {
background: #8FC561;
}
.clear {
clear: both;
}
/* 120px x 120px square; this will create a black 20px frame on the inside */
.boxtest-wrapper {
width: 100px;
height: 100px;
float: left;
background: black;
color: white;
margin: 1em;
padding: 20px;
}
#boxtest-4-container {
width: 100%;
height: 100%;
}
.boxtest {
width: 100%;
height: 100%;
background: white;
color: black;
border: 5px solid green;
overflow: hidden;
}
</style>
<script type="text/javascript">
function addBorderBox() {
var wrap1 = document.getElementById("wrap-1");
var wrap2 = document.getElementById("wrap-2");
var borderBox = document.createElement("div");
borderBox.className = "test border-box";
var borderBoxFill = document.createElement("div");
borderBoxFill.className = "fill";
var borderBoxContent = document.createTextNode("Generated border box fill");
borderBoxFill.appendChild(borderBoxContent);
borderBox.appendChild(borderBoxFill);
var gauge = document.createElement("div");
gauge.className = "gauge";
var gaugeText1 = "width: 100px";
var gaugeText2 = "height: 100%";
var gaugeText3 = "bottom should be visible";
gauge.appendChild(document.createTextNode(gaugeText1));
gauge.appendChild(document.createElement("br"));
gauge.appendChild(document.createTextNode(gaugeText2));
gauge.appendChild(document.createElement("br"));
gauge.appendChild(document.createTextNode(gaugeText3));
wrap1.appendChild(borderBox);
wrap2.appendChild(gauge);
}
</script>
</head>
<body id="body" class="border-box">
<div id="header">
<p>Header - 50px;</p>
</div>
<div id="content" class="border-box">
<div id="nested-header">
<p>Nested Header - 40px;</p>
</div>
<div id="nested-content-wrap">
<div id="nested-floater">
<p>Float - 100px;</p>
<ul>
<li>This element should never scroll.</li>
</ul>
</div>
<div id="nested-content">
<div id="inner-nest">
<div id="inner-head">
<p>Inner Head - 30px;</p>
</div>
<div id="inner-content" class="border-box">
<div style="float: right; ">
<p>The fourth square should look just like the other three:</p>
<div id="boxtest-wrapper-1" class="boxtest-wrapper">
<div id="boxtest-1" class="boxtest border-box"></div>
</div>
<div id="boxtest-wrapper-2" class="boxtest-wrapper">
<div id="boxtest-2" class="boxtest border-box"></div>
</div>
<br class="clear" />
<div id="boxtest-wrapper-3" class="boxtest-wrapper">
<div id="boxtest-3" class="boxtest border-box"></div>
</div>
<div id="boxtest-wrapper-4" class="boxtest-wrapper">
<div id="boxtest-4-container">
<!-- boxtest-4-container isn't special in any way. it just has width and height set to 100%. -->
<div id="boxtest-4" class="boxtest border-box"></div>
</div>
</div>
</div>
<p>Inner Content - fluid</p>
<ul>
<li>The top of the scrollbar should be covered by the “Inner Head” element.</li>
<li>The bottom of the scrollbar should be visible without having to scroll “Inner Head” out of view.</li>
</ul>
<p>Document Compat Mode:
<strong id="compatMode">
<script type="text/javascript">
var compatMode = document.compatMode;
if (compatMode != "CSS1Compat") {
document.getElementById("compatMode").style.color = "red";
}
document.write(compatMode);
</script>
</strong>
</p><br />
<div class="notes">
<h2>Notes</h2>
<ul>
<li>In IE6 and IE7 (and possibly IE8; untested), you'll notice a slight shift of contents that have <code>box-sizing</code> set to <code>border-box</code>. This is the amount of time it takes for box-sizing.htc to finish downloading.</li>
<li>This workaround is not live. Anything that causes a reflow or repaint will not currently trigger an update to widths and heights of <code>border-box</code> elements.</li>
<li>See http://webfx.eae.net/dhtml/boxsizing/boxsizing.html for the original solution to the IE6/IE7 <code>border-box</code> problem. box-sizing.htc has been modified to allow for percentage widths and heights.</li>
<li>To see what this example should look like without the use of box-sizing.htc, view it in Firefox or IE8.</li>
</ul>
</div>
<br class="clear" />
<form>
<fieldset>
<legend>DOM Update Test</legend>
<input type="button" value="Click to add border-box" onclick="addBorderBox(); " />
</fieldset>
</form>
<div id="wrap-1" class="wrap">
<div class="test content-box" id="content-box-1" style="border-width: 5px; border-style: solid;">
<div class="fill">Content box fill</div>
</div>
<div class="test content-box" id="content-box-2" style="border-width: 5px; border-style: solid; padding: 5px;">
<div class="fill">Content box fill</div>
</div>
<div class="test border-box" id="border-box-1" style="border-width: 5px; border-style: solid;">
<div class="fill">Border box fill</div>
</div>
<div class="test border-box" id="border-box-2" style="border-width: 5px; border-style: solid; padding: 5px;">
<div class="fill">Border box fill</div>
</div>
<div class="test" id="default-box-1" style="border-width: 5px; border-style: solid;">
<div class="fill">Default box fill</div>
</div>
<div class="test" id="default-box-2" style="border-width: 5px; border-style: solid; padding: 5px;">
<div class="fill">Default box fill</div>
</div>
</div>
<div id="wrap-2" class="wrap">
<!-- subtract 1 from width for 1px right border -->
<div class="gauge" style="width: 129px;">width: 130px<br />height: 100%<br />bottom should be cut off</div>
<div class="gauge" style="width: 119px;">width: 120px<br />height: 100%<br />bottom should be cut off</div>
<div class="gauge">width: 100px<br />height: 100%<br />bottom should be visible</div>
<div class="gauge">width: 100px<br />height: 100%<br />bottom should be visible</div>
<div class="gauge" style="width: 129px;">width: 130px<br />height: 100%<br />bottom should be cut off</div>
<div class="gauge" style="width: 119px;">width: 120px<br />height: 100%<br />bottom should be cut off</div>
</div>
<br class="clear" />
<script type="text/javascript">
var lipsum = "<p>Lorem ipsum dolor sit amet.</p>";
for (var i = 0; i < 100; i++) {
document.write(lipsum);
}
</script>
</div>
</div>
</div>
</div>
<div id="nested-footer">
<p>Nested Footer - 40px;</p>
</div>
</div>
<div id="footer">
<p>Footer - 50px;</p>
</div>
</body>
</html>
If by covering up part of the page, you mean the page displayed in the iframe, one thought might be to add a top margin to your iframe, using the margin-top: property in CSS. This would eliminate the scroll bar given that you properly constrained the height of the iframe.
Android Kotlin Answer
For example, I am using padding for iFrame of WebView in this way:
val url = "www.stackoverflow.com"
val iframeExample = "<html><body style=\"margin: 0; padding: 0\"><iframe width=\"100%\" src=\"$url\" frameborder=\"0\" allowfullscreen></iframe></body></html>"
webView.loadData(iframeExample, "text/html", "utf-8")