Making a input range that perfectly aligns with numbers above it - html

I have a slider that goes from 1 to 12. I would like the thumb to perfectly align with all the numbers above it when I move it up and down.
This is what I have so far, but as you can see, it is still slightly off.
Is there a way to achieve this?
body {
height: 100vh;
display: flex;
}
.container {
margin: auto;
width: 400px;
}
span {
display: block;
width: 1ch;
}
.numbers {
display: flex;
justify-content: space-between;
padding-left: .4em;
}
<div class="container">
<div class="numbers">
<span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span><span>9</span><span>10</span><span>11</span><span>12</span>
</div>
<input style="width: 100%;" type="range" min="1" max="12" name="" id="" />
</div>

We can configure the number spans so they all have the same width and center text alignment. By setting their initial width to zero we negate the effect of their contents, which vary in size (1 vs 10, for example).
We can use flexbox on the slider as well, giving it the same flex-grow value as twice our 12 numbered spans. This lets us use half-widths for spacing. We add a span on each side of it with a value of half that of the numbered spans, shifting things over properly.
Finally, some margin tweaks get things pixel-perfect (in Chrome, at least).
Note that I've changed the primary width to a relative value so you can see that this works at any size. Have a look at the full screen demo.
The primary drawback here is that we have quantities hard-coded in the CSS. If the slider range changes, so must the CSS. Ideally we'd find a fully flexible solution.
If I'm not making sense, have a look at https://css-tricks.com/snippets/css/a-guide-to-flexbox.
body {
height: 100vh;
display: flex;
}
.container {
margin: auto;
width: 75vw;
}
.numbers,
.slider {
display: flex;
justify-content: space-between;
}
.numbers span,
.slider span {
width: 0;
flex-grow: 1;
text-align: center;
}
.slider span {
flex-grow: 1;
}
.slider input {
flex-grow: 24;
margin-left: -2px; /* account for UI sizing */
margin-right: -2px; /* account for UI sizing */
}
<div class="container">
<div class="numbers">
<span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span><span>9</span><span>10</span><span>11</span><span>12</span>
</div>
<div class="slider">
<span><!-- half --></span>
<input type="range" min="1" max="12" name="" value="1" id="" />
<span><!-- half --></span>
</div>
</div>

I think they can't be easily arranged, according to the idea you have to play with a margin left right or width : 0%; etc ...
If you want it is an alternative
const range = document.getElementById("range"),
rangeV = document.getElementById("rangeV"),
setValue = () => {
const newValue = Number(((range.value - range.min) * 100) / (range.max - range.min)),
newPosition = 10 - newValue * 0.2;
rangeV.innerHTML = `<span>${range.value}</span>`;
rangeV.style.left = `calc(${newValue}% + (${newPosition}px))`;
};
document.addEventListener("DOMContentLoaded", setValue);
range.addEventListener("input", setValue);
body {
min-height: 100vh;
padding: 0 10vh;
margin: 0;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
input[type="range"] {
-webkit-appearance: none;
margin: 20px 0;
width: 100%;
}
input[type="range"]:focus {
outline: none;
}
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: 4px;
cursor: pointer;
animate: 0.2s;
background: #03a9f4;
border-radius: 25px;
}
input[type="range"]::-webkit-slider-thumb {
height: 20px;
width: 20px;
border-radius: 50%;
background: #fff;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 1);
cursor: pointer;
-webkit-appearance: none;
margin-top: -8px;
}
input[type="range"]:focus::-webkit-slider-runnable-track {
background: #03a9f4;
}
.range-wrap {
width: 500px;
position: relative;
}
.range-value {
position: absolute;
top: -50%;
}
.range-value span {
width: 30px;
height: 24px;
line-height: 24px;
text-align: center;
background: #03a9f4;
color: #fff;
font-size: 12px;
display: block;
position: absolute;
left: 50%;
transform: translate(-50%, 0);
border-radius: 6px;
}
.range-value span:before {
content: "";
position: absolute;
width: 0;
height: 0;
border-top: 10px solid #03a9f4;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
top: 100%;
left: 50%;
margin-left: -5px;
margin-top: -1px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Input Range with Dynamic Label</title>
</head>
<body>
<div class="range-wrap">
<div class="range-value" id="rangeV"></div>
<input id="range" type="range" min="1" max="12" value="1" step="1" />
</div>
</body>
</html>

Related

Changing the order of elements created using ::before and ::after in CSS

I've tried to simplify my problem into the below:
.wrapper {
position: relative;
display: inline-flex;
min-height: 1.5rem;
border: 1px solid black;
margin-right: 1rem;
padding-right: 1.5rem;
}
.input {
position: absolute;
z-index: -1;
opactiy: 0;
}
.label-wrapper {
margin-left: 2rem;
}
.label {
position: relative;
margin-bottom: 0;
}
.label:before {
position: absolute;
top: 4px;
left: -24px;
display: block;
width: 20px;
height: 20px;
pointer-events: none;
content: "";
background-color: #fff;
}
.label:after {
position: absolute;
top: 4px;
left: -24px;
display: block;
height: 40px;
content: "";
background-repeat: no-repeat;
background-position: center center;
background-size: 50% 50%;
}
<div class="wrapper">
<input class="input" type="checkbox"></input>
<label class="label">
<div class="label-wrapper">
Option 1
</div>
</label>
</div>
In addition to this, I have the following CSS (in a StyledComponent) that adds a "check" to the checkbox when the user clicks on the hidden input in the .input:
&[type="checkbox"]:checked ~ label::after {
background-image: url("${checkboxImage}");
top: -2px;
left: -29px;
width: 30px;
height: 30px;
}
This means it behaves as a checkbox should - however, I want to swap my elements around so that the checkbox sits to the right of the text instead of the left, to do this I have tried re-ordering the input so that it comes after the label but then the hidden input (which is handling the actual click behaviour is disjointed from the CSS checkbox? Can anyone point me in the direction of how I might resolve this?
Summary:
Using :before & :after to create a visual checkbox, but the logic for that checkbox is actually handled by input (which is hidden) - how can I move both the visual & hidden input to the right of the text?
Edit:
Its very simple with display: flex and flex-direction: row-reverse.
.label-wrapper {
margin-left: 24px;
margin-right: 0;
flex-grow: 1; /* ADDED THIS */
}
.label {
position: relative;
margin-bottom: 0;
display:flex;
flex-direction: row;
flex: 1; /* ADDED THIS */
}
.label.reverse{
flex-direction: row-reverse;
}
See the Snippet below:
.wrapper {
position: relative;
display: inline-flex;
min-height: 1.5rem;
border: 1px solid black;
margin-right: 1rem;
padding: 0.5rem;
width: 200px;
}
.input {
position: absolute;
z-index: -1;
visibility: hidden;
}
.label-wrapper {
margin-left: 24px;
margin-right: 0;
flex-grow: 1;
}
.label.reverse > .label-wrapper {
margin-left: 0;
margin-right: 24px;
}
.label {
position: relative;
margin-bottom: 0;
display:flex;
flex-direction: row;
flex: 1;
}
.label.reverse{
flex-direction: row-reverse;
}
.label:before {
position:absolute;
display: block;
width: 20px;
height: 20px;
content: "";
background-color: #fff;
border: 1px solid black;
border-radius:4px;
}
.label:after {
position: absolute;
display: block;
height: 20px;
content: "";
background-repeat: no-repeat;
background-position: center center;
background-size: 80%;
}
input[type="checkbox"]:checked ~ .label::after {
background-image: url("https://cdn-icons-png.flaticon.com/512/447/447147.png");
width: 20px;
height: 20px;
}
<div class="wrapper">
<input class="input input1" name="checkbox1" id="checkbox1" type="checkbox">
<label class="label" for="checkbox1">
<div class="label-wrapper">
Option 1
</div>
</label>
</div>
<div class="wrapper">
<input class="input input2" name="checkbox2" id="checkbox2" type="checkbox">
<label class="label reverse" for="checkbox2">
<div class="label-wrapper">
Option 2
</div>
</label>
</div>
Are you trying to change the left to right default position of elements?
If that's the case you can use text-align or float. Or even flexbox.
Also, put the text inside a span or something so you can control it.
If I have understood you correctly, there are many ways based on context like using absolute positioning, or put the label before input and close it. or something like this:
<label class="">
<span class="">text</span>
<input class="" type="checkbox" name="order">
</label>

How can I keep an image from overflowing its container?

I'm working with Reactjs in a page... like a diary.
At the end of the page, there is an img that I'm trying to set inside the page but because of the size, it goes out of the page... I try to modify it with Css, but still not working. Can you help me please?
This is how the page looks:
This is how the html code looks:
<div className="notes__content">
<input type="text" placeholder="Somer awesome title" className="notes__title-input" autoComplete="off"/>
<textarea placeholder="What happened today?" className="notes__textarea"></textarea>
<div className="notes__image">
<img src="https://images.pexels.com/photos/4173624/pexels-photo-4173624.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="imagen"/>
</div>
</div>
This is how I set the css:
.notes__main-content{
display: flex;
flex-direction: column;
height: 100%;
}
.notes__appbar{
align-items: center;
background-color: $primary;
color: white;
display: flex;
justify-content: space-between;
padding: 10px 20px 10px 20px;
}
.notes__content{
display: flex;
flex-direction: column;
height: 100%;
padding: 20px;
}
.notes__title-input, .notes__textarea{
border: none;
&:focus{
outline: none;
}
}
.notes__title-input{
color: $dark-grey;
font-size: 25px;
font-weight: 700;
margin-bottom: 10px;
}
.notes__textarea{
border: none;
color: $dark-grey;
font-size: 20px;
flex: 1 1 auto;
resize: none;
}
.notes__image{
box-shadow: 5px 5px $dark-grey;
height: 150px;
}
To be clear, what I want to do is to set the img to 150px so it can fit my page. Thank you for your help
You can add another div inside notes__image div. Lets call it notes__image__inner with a div wrapper.
<div className="notes__content">
<input type="text" placeholder="Somer awesome title" className="notes__title-input" autoComplete="off"/>
<textarea placeholder="What happened today?" className="notes__textarea"></textarea>
<div className="notes__image">
<div className="notes__inner__image">
<img src="https://images.pexels.com/photos/4173624/pexels-photo-4173624.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="imagen"/>
</div>
</div>
</div>
Update the notes__image and img CSS with this:
.notes__image {
box-shadow: 5px 5px $dark-grey;
height: 150px;
position: relative;
}
.notes__inner__image {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.notes__inner__image img {
width: 100%;
position: static;
height: 100%;
object-fit: cover;
}
Images don't magically shrink to fit their containers. You need to tell them to do so:
.notes__image img {
max-width: 100%; /* <-- here's your huckleberry */
}
You don't want to use the width property as that'll stretch images beyond their native size, and you don't want to set height as that will goof up aspect ratio.
Here I've converted className to class for demonstration purposes. If you view the fullscreen demo and shrink the window size you can see it in action.
.notes__main-content {
display: flex;
flex-direction: column;
height: 100%;
}
.notes__appbar {
align-items: center;
background-color: $primary;
color: white;
display: flex;
justify-content: space-between;
padding: 10px 20px 10px 20px;
}
.notes__content {
display: flex;
flex-direction: column;
height: 100%;
padding: 20px;
}
.notes__title-input,
.notes__textarea {
border: none;
&:focus {
outline: none;
}
}
.notes__title-input {
color: $dark-grey;
font-size: 25px;
font-weight: 700;
margin-bottom: 10px;
}
.notes__textarea {
border: none;
color: $dark-grey;
font-size: 20px;
flex: 1 1 auto;
resize: none;
}
.notes__image {
box-shadow: 5px 5px $dark-grey;
height: 150px;
}
.notes__image img {
max-width: 100%; /* <-- here's your huckleberry */
}
<div class="notes__content">
<input type="text" placeholder="Somer awesome title" class="notes__title-input" autoComplete="off" />
<textarea placeholder="What happened today?" class="notes__textarea"></textarea>
<div class="notes__image">
<img src="https://images.pexels.com/photos/4173624/pexels-photo-4173624.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="imagen" />
</div>
</div>
The className property is used in React. Is this a React application? If not, it needs to be revised to "class".
Also make sure your image does not overflow the bounds of the div. You can set strict width and height in the image by using the img tag's "width" and "height" properties. Or create a notes__image img declaration, like this:
.notes__image img {
width: 100%;
height: 100%;
}

how to restrict the autocomplete div tags height without affecting the following field

[![How to restrict the autocomplete div tags height without affecting the bottom fields.
Here when i'm searching for country references dropdown is showing, but the entire height is increasing.
here the dropdown is fall over the communication field. How to achieve this. Please find the PIC for better understanding Thanks.`
Country Reference
<div class="form-group right">
<label for="Communication_Type" class="label-title">Communication Type</label>
<div class="autocomplete1">
<input type="text" class="" id="empid1" name="empid1">
<div class="dialog1">
<ul id="charactersList1"></ul>
</div>
</div>
</div>
.cref_container {
background-color: yellow;
}
.label_cref {
display: inline-block;
margin-left: 25px;
padding: 5px;
width: 30%;
margin-top: 2px;
background-color: royalblue;
}
.autocomplete {
/* background: #fff; */
position: relative;
}
.autocomplete .close {
position: absolute;
font-size: 13px;
z-index: 10;
top: 10px;
left: calc(100% - 50px);
color: #aaa;
cursor: pointer;
display: none;
}
.autocomplete .close.visible {
display: block;
}
.dialog {
width: 60%;
margin-left: 40%;
display: none;
min-height: 40px;
max-height: 330px;
overflow: scroll;
border-top: 1px solid #f4f4f4;
}
.dialog.open {
display: block;
}
.dialog div {
padding: 20px 10px;
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.dialog div:hover {
background: #f2f2f2;
}`]1]1
You have two options:
either use a native "select" input component which already does that (see https://www.w3schools.com/tags/tag_select.asp)
set your "dialog1"'s position to "fixed" and set its "left" and "top" from javascript. "fixed" position takes it out of the normal layout and doesn't push around any other elements.
const leftCoordinate = 20;
const topCoordinate = 100;
document.getElementsByClassName("dialog1")[0].style.left = leftCoordinate;
document.getElementsByClassName("dialog1")[0].style.top = topCoordinate;
.dialog1 {
position: fixed;
}

Absolutely positioned black div with opacity does not cover a certain element and I can't figure out why

I have a modal window which has an absolutely positioned black div that covers the entire viewport whenever the modal window is open. For some reason though this window doesn't cover a certain element even though it goes over it. Everything else is covered by the black screen just fine so I have no idea why this specific element doesn't.
.black-screen {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.8);
}
The element that is not being covered:
<div class="form-container">
<form class='send-message'>
<input class='message-input' placeholder="Type a message">
</form>
</div>
And the CSS of that element:
.form-container {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.send-message {
position: relative;
padding: 20px 0px 20px 20px;
flex: 1;
}
.message-input {
width: 100%;
padding: 15px;
outline: none;
border: none;
background-color: #40444b;
color: #dcddde;
font-size: 14px;
border-radius: 5px 0 0 5px;
}
With small chunk of css I can only guess (css is a cascade and is hereditary)
.form-container {
position: relative; /* remove this */
display: flex;
justify-content: center;
align-items: center;
}
.send-message {
position: relative; /* remove this */
padding: 20px 0px 20px 20px;
flex: 1;
}
.message-input {
width: 100%;
padding: 15px;
outline: none;
border: none;
background-color: #40444b;
color: #dcddde;
font-size: 14px;
border-radius: 5px 0 0 5px;
}
If for whatever reasons this is not possible or it doesn't work - replace div elements but I don't know if this will work in every browser ...
<div class="form-container">
<form class='send-message'> <input class='message-input' placeholder="Type a message"> </form>
</div>
<div class="black-screen">black</div>
If the problem persists, use Validator w3c to find out how bad it is
... in fact, use Validator no matter what

css for 2 inc/dec buttons by an input that reposition properly when resizing screen

I want to display an input box in html and 2 small buttons to the right, one on top of each other. Something like this
https://jsfiddle.net/danaya/yw94f0Lt/3/
The html code is simple
<div class="list">
<div class="name">product</div>
<div class="input">
<input type="text" size="3" value="1">
<div class="inc">+</div>
<div class="dec">-</div>
</div>
<div class="price">2.99</div>
</div>
And this is the css
.list {
display: flex;
}
.name,
.input,
.price {
padding: 10px 10px;
border: 1px solid red;
}
.name {
width: 50%;
}
.input,
.price {
text-align: right;
width: 25%;
}
.input {
position: relative;
top: -5px;
}
input {
line-height: 25px;
}
.inc,
.dec {
display: block;
position: absolute;
width: 13px;
height: 13px;
background-color: #999;
text-align: center;
color: #fff;
line-height: 12px;
}
.inc {
top: 11px;
left: 40px;
}
.dec {
top: 25px;
left: 40px;
}
As it is right now, when I resize the window, the div.input is resized and so the buttons, being related to the input, lose their position by the input element.
I need to keep the flex display in the .list element, but other than that I can change anything. I also need the buttons to not increase the width of the div.input element, that's why I'm using the position:relative.
Any ideas?
Thanks
Would this work for you?
.list {
display: flex;
align-items: center;
}
.name,
.price {
padding: 0 10px;
}
.input, input {
box-sizing: border-box; /*to set the equal height to bot .input and input*/
height: 31px; /*13 + 13 (buttons) + 5 (paddings for buttons) = 31px */
}
.input {
position: relative;
/*width: 25%; Use this if you want to increate the width of your div.input*/
}
input {
padding-right: 15px; /* 15px set so that input characters do not go underneath the + and - buttons */
width: 100%; /* set 100% so that input will take 100% width of its parent size */
}
.inc,
.dec {
box-sizing: border-box;
display: block;
position: absolute;
width: 13px;
height: 13px;
background-color: #999;
text-align: center;
color: #fff;
line-height: 12px;
}
.inc {
top: 2px;
right: 2px;
}
.dec {
bottom: 2px;
right: 2px;
}
<div class="list">
<div class="name">product</div>
<div class="input">
<input type="text" size="3" value="1">
<span class="inc">+</span>
<span class="dec">-</span>
</div>
<div class="price">2.99</div>
</div>