How to get value text to follow slider input? - css

I've created a Slider in react.
It looks like this:
import styles from '../Slider.scss';
type Props = {|
maxValue: Number,
minValue: Number,
onChange: Function,
step?: Number,
value: Number
|};
const SliderInput = (props: Props) => {
const ratio = (props.value - props.minValue) / (props.maxValue - props.minValue);
return (
<div className={styles[`slider-container`]}>
<div className={styles.labels}>
<span>${props.minValue}</span>
<span>${props.maxValue}</span>
</div>
<div>
<input
className={styles.slider}
max={props.maxValue}
min={props.minValue}
onChange={props.onChange}
step={props.step}
type="range"
value={props.value}
/>
<div className={styles[`slider-value`]}>
<span>${props.value}</span>
</div>
</div>
</div>
);
};
The styles look like this:
.slider-container {
width: 100%;
}
.slider {
-webkit-appearance: none;
background: transparent;
width: 100%;
height: 25px;
background-image: linear-gradient(to right, #F5F5F5, #A5D8F5);
outline: none;
}
.slider-value {
/* Not sure what goes here yet */
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 30px;
height: 30px;
background: black;
cursor: pointer;
}
.labels {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
What I'm trying to accomplish:
I want the value of the slider to show up right above or below the current position of the slider input. I'm thinking I'll have to give the slider-value a position: absolute, but I'm not sure what to do beyond that.

First we add position relative to .slider-value and we need to match the width of the input[type=range] because we gonna move the span along it using the left property.
.slider-value {
position: relative;
/* it's for because left moves the element relative to it's left not the middle */
width:calc(100% - 30px);
}
.slider-value>span {
position: absolute;
text-align: center;
/* must match the thumb width */
width: 30px;
}
im not going to go over how you update the value, im just going to tell you how to use it,
so we gonna assign the value of the slider to the left property of the span,
should be getting updated and passed as props to the slider something like:
<span style={{left:this.props.value+"%"}} >{this.props.value}</span>
this would work fine the minValue equals 0 and the maxValue equals 100, however this won't be the only case, so we map the value.
The map function should look like this, i just copied from the p5.js lib
map(n, start1, stop1, start2, stop2) {
return ((n-start1)/(stop1-start1))*(stop2-start2)+start2;
}
The span then should look like this
<span style={{this.map(this.props.value,this.props.minValue,this.props.maxValue,0,100)+"%"}} >{this.props.value}</span>
And if you have any question, please don't hesitate, i know i'm good at explaining. :)
EDIT
Live Demo
Code

Related

How to auto animate element every time when it changes position on the screen?

I have vue project.
Every time some elements on the page disappear because of v-if the rest of the page is slightly rearranged. I want it to happen smoothly.
All elements have :key attribute.
Example:
I have centred 2 boxes in one row. When one is gone, the second one is still centred, so changes position.
image
How to handle this?
EDIT 1
I tried:
<div>
<CompoentA :key=345 class="one-line" v-show="showComponentA" />
<transition name="moving">
<CompoentB class="one-line" :key=123 />
</transition>
</div>
.one-line { display: inline-table; }
.moving-move { transition: transform 1s; }
v-if will remove the element from the DOM, so you can't animate your disappearing components.
You should use v-show instead if you want to animate them (they will stay hidden in the DOM).
I think that you need "from" and "to" values to create this animation. When you remove the elemnt from DOM, the other elements will be placed based on a "inline" position, so there is no value reference to create a transition.
There is a similar problem here, where a transition with height:0 and height: auto
How can I transition height: 0; to height: auto; using CSS?
I made a sample to solve this using a width (bigger than content) and width 0 with opacity 0 to hide the inner content. To run this sample, simple click in items, it will be "removed" (opacity:0 and width: 0) and the transition works because there is a initial width set (80px).
new Vue({
el: "#app",
data: () => ({
// yes, there is better ways, but let make this sample "simple"
letters: ['a', 'b', 'c', 'd'],
visible: {
a: true,
b: true,
c: true,
d: true,
}
})
})
#app {
/* decoration, you can remove */
width: 100%;
text-align: center;
background-color: #f4f4f4;
}
.moving {
/* margin and padding 0
because the width content will be set to 0
if this element has a margin, when removed the margin still display the "space"
*/
padding: 0;
margin: 0;
font-size: 0; /* remove white space in DOM element */
display: inline-block;
opacity: 1;
transition: width linear .2s;
/* decoration, you can remove */
width: 80px;
border: 1px dotted #ccc;
cursor: pointer;
}
.moving-content {
font-size: 18px; /* restore font size */
display: inline-block;
/* decoration, you can remove */
background-color: #2af;
color: white;
padding: 20px;
box-sizing: border-box;
}
.moving.hidden {
width: 0px;
opacity: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="letter in letters"
:key="letter"
:class="{ moving: true, hidden: !visible[letter] }" #click="visible[letter] = false">
<span class="moving-content">
{{ letter }}
</span>
</div>
</div>
References:
https://stackoverflow.com/a/40785144/1724128
https://stackoverflow.com/a/53127208/1724128

How to make my element take 100% of the screen width even if it is inside an element that take 80% of the screen?

I am working on a ReactJS project and I am facing a CSS problem. I will explain exactly what I want to achieve and what I have done so far.
My fluidContainer is the div with the gray background.
Here is what I have now :
And here is what I want to achieve, I want that space to be eliminated :
I used negative margins and made my fluid-container larger but it is bad code for me, so here is my react component :
const FluidContainer = props => (
<div
className="co-fluid-container"
>
{props.children}
</div>
);
And here is my sass file and what I have tried already :
#import "../../appConstants/style/cssVariables.scss";
.co-fluid-container {
//TODO: améliorer la précision
margin: 0 ( calc( (#{$container-width} + (#{$grid-gutter}/2) - 99vw) /2) );
padding: 40px (calc((100vw - #{$container-width} - (#{$grid-gutter}/2))/2));
&--fluid-content {
padding: 40px 20px;
}
#media($extra-small){
// a justifier
width:calc(100vw + #{$grid-gutter}*5);
margin-left: calc(-#{$grid-gutter}*3/2);
}
#media($small) {
// a justifier
width: calc(100vw + #{$grid-gutter}*5);
margin: 0 calc(-#{$grid-gutter}*3);
padding: 40px calc(#{$grid-gutter}*3);
}
#media($medium){
width:calc(110vw);
margin-left: calc(-#{$grid-gutter}*3/2);
padding: 40px calc(#{$grid-gutter}*3);
}
#media($large){
margin: 0 ( calc( (#{$container-width} + (#{$grid-gutter}/2) - 100vw) /2));
padding: 40px (calc((100vw - #{$container-width} - (#{$grid-gutter}/2))/2));
}
}
This code is causing me problem, when I try to make my page responsive, here are the variables I used in my code :
grid-gutter : 32 px;
container: 1170px;
extra-small: "max-width: 599px"
medium and large and small are breakpoints too ..
Here is a solution I have tried also, is using relative and absolute positioning but still get a problem, so I changed my rendered element to this :
const FluidContainer = props => (
<div className="co-fluid-conteneur">
<div className="co-fluid-container">{props.children}</div>
</div>
);
and that is my style :
.co-fluid-conteneur {
position: relative;
height: 300px;
}
.co-fluid-container {
position: absolute;
width: 100vw;
}
but those are the results :
Any help would be much appreciated.
For a quick example:
Take the code for the main html file or element as:
<div className="parent">
<div className="child">
</div>
</div>
CSS looks like this:
.parent {
position: relative;
width: 50vw;
height: 50vh;
background-color: blue;
}
.child {
position: absolute;
width: 100vw;
height: 40vh;
background-color: rgba(255, 0, 0, 0.50);
}
This will produce the following layout. (vw is a measure of the viewport width, so 50vw is 50% of the Viewport Width).

Chatbox component - Flex item with scrollable content [duplicate]

Here is an example chat app ->
The idea here is to have the .messages-container take up as much of the screen as it can. Within .messages-container, .scroll holds the list of messages, and in case there are more messages then the size of the screen, scrolls.
Now, consider this case:
The user scrolls to the bottom of the conversation
The .text-input, dynamically gets bigger
Now, instead of the user staying scrolled to the bottom of the conversation, the text-input increases, and they no longer see the bottom.
One way to fix it, if we are using react, calculate the height of text-input, and if anything changes, let .messages-container know
componentDidUpdate() {
window.setTimeout(_ => {
const newHeight = this.calcHeight();
if (newHeight !== this._oldHeight) {
this.props.onResize();
}
this._oldHeight = newHeight;
});
}
But, this causes visible performance issues, and it's sad to be passing messages around like this.
Is there a better way? Could I use css in such a way, to express that when .text-input-increases, I want to essentially shift up all of .messages-container
2:nd revision of this answer
Your friend here is flex-direction: column-reverse; which does all you ask while align the messages at the bottom of the message container, just like for example Skype and many other chat apps do.
.chat-window{
display:flex;
flex-direction:column;
height:100%;
}
.chat-messages{
flex: 1;
height:100%;
overflow: auto;
display: flex;
flex-direction: column-reverse;
}
.chat-input { border-top: 1px solid #999; padding: 20px 5px }
.chat-input-text { width: 60%; min-height: 40px; max-width: 60%; }
The downside with flex-direction: column-reverse; is a bug in IE/Edge/Firefox, where the scrollbar doesn't show, which your can read more about here: Flexbox column-reverse and overflow in Firefox/IE
The upside is you have ~ 90% browser support on mobile/tablets and ~ 65% for desktop, and counting as the bug gets fixed, ...and there is a workaround.
// scroll to bottom
function updateScroll(el){
el.scrollTop = el.scrollHeight;
}
// only shift-up if at bottom
function scrollAtBottom(el){
return (el.scrollTop + 5 >= (el.scrollHeight - el.offsetHeight));
}
In the below code snippet I've added the 2 functions from above, to make IE/Edge/Firefox behave in the same way flex-direction: column-reverse; does.
function addContent () {
var msgdiv = document.getElementById('messages');
var msgtxt = document.getElementById('inputs');
var atbottom = scrollAtBottom(msgdiv);
if (msgtxt.value.length > 0) {
msgdiv.innerHTML += msgtxt.value + '<br/>';
msgtxt.value = "";
} else {
msgdiv.innerHTML += 'Long long content ' + (tempCounter++) + '!<br/>';
}
/* if at bottom and is IE/Edge/Firefox */
if (atbottom && (!isWebkit || isEdge)) {
updateScroll(msgdiv);
}
}
function resizeInput () {
var msgdiv = document.getElementById('messages');
var msgtxt = document.getElementById('inputs');
var atbottom = scrollAtBottom(msgdiv);
if (msgtxt.style.height == '120px') {
msgtxt.style.height = 'auto';
} else {
msgtxt.style.height = '120px';
}
/* if at bottom and is IE/Edge/Firefox */
if (atbottom && (!isWebkit || isEdge)) {
updateScroll(msgdiv);
}
}
/* fix for IE/Edge/Firefox */
var isWebkit = ('WebkitAppearance' in document.documentElement.style);
var isEdge = ('-ms-accelerator' in document.documentElement.style);
var tempCounter = 6;
function updateScroll(el){
el.scrollTop = el.scrollHeight;
}
function scrollAtBottom(el){
return (el.scrollTop + 5 >= (el.scrollHeight - el.offsetHeight));
}
html, body { height:100%; margin:0; padding:0; }
.chat-window{
display:flex;
flex-direction:column;
height:100%;
}
.chat-messages{
flex: 1;
height:100%;
overflow: auto;
display: flex;
flex-direction: column-reverse;
}
.chat-input { border-top: 1px solid #999; padding: 20px 5px }
.chat-input-text { width: 60%; min-height: 40px; max-width: 60%; }
/* temp. buttons for demo */
button { width: 12%; height: 44px; margin-left: 5%; vertical-align: top; }
/* begin - fix for hidden scrollbar in IE/Edge/Firefox */
.chat-messages-text{ overflow: auto; }
#media screen and (-webkit-min-device-pixel-ratio:0) {
.chat-messages-text{ overflow: visible; }
/* reset Edge as it identifies itself as webkit */
#supports (-ms-accelerator:true) { .chat-messages-text{ overflow: auto; } }
}
/* hide resize FF */
#-moz-document url-prefix() { .chat-input-text { resize: none } }
/* end - fix for hidden scrollbar in IE/Edge/Firefox */
<div class="chat-window">
<div class="chat-messages">
<div class="chat-messages-text" id="messages">
Long long content 1!<br/>
Long long content 2!<br/>
Long long content 3!<br/>
Long long content 4!<br/>
Long long content 5!<br/>
</div>
</div>
<div class="chat-input">
<textarea class="chat-input-text" placeholder="Type your message here..." id="inputs"></textarea>
<button onclick="addContent();">Add msg</button>
<button onclick="resizeInput();">Resize input</button>
</div>
</div>
Side note 1: The detection method is not fully tested, but it should work on newer browsers.
Side note 2: Attach a resize event handler for the chat-input might be more efficient then calling the updateScroll function.
Note: Credits to HaZardouS for reusing his html structure
You just need one CSS rule set:
.messages-container, .scroll {transform: scale(1,-1);}
That's it, you're done!
How it works: First, it vertically flips the container element so that the top becomes the bottom (giving us the desired scroll orientation), then it flips the content element so that the messages won't be upside down.
This approach works in all modern browsers. It does have a strange side effect, though: when you use a mouse wheel in the message box, the scroll direction is reversed. This can be fixed with a few lines of JavaScript, as shown below.
Here's a demo and a fiddle to play with:
//Reverse wheel direction
document.querySelector('.messages-container').addEventListener('wheel', function(e) {
if(e.deltaY) {
e.preventDefault();
e.currentTarget.scrollTop -= e.deltaY;
}
});
//The rest of the JS just handles the test buttons and is not part of the solution
send = function() {
var inp = document.querySelector('.text-input');
document.querySelector('.scroll').insertAdjacentHTML('beforeend', '<p>' + inp.value);
inp.value = '';
inp.focus();
}
resize = function() {
var inp = document.querySelector('.text-input');
inp.style.height = inp.style.height === '50%' ? null : '50%';
}
html,body {height: 100%;margin: 0;}
.conversation {
display: flex;
flex-direction: column;
height: 100%;
}
.messages-container {
flex-shrink: 10;
height: 100%;
overflow: auto;
}
.messages-container, .scroll {transform: scale(1,-1);}
.text-input {resize: vertical;}
<div class="conversation">
<div class="messages-container">
<div class="scroll">
<p>Message 1<p>Message 2<p>Message 3<p>Message 4<p>Message 5
<p>Message 6<p>Message 7<p>Message 8<p>Message 9<p>Message 10<p>Message 11<p>Message 12<p>Message 13<p>Message 14<p>Message 15<p>Message 16<p>Message 17<p>Message 18<p>Message 19<p>Message 20
</div>
</div>
<textarea class="text-input" autofocus>Your message</textarea>
<div>
<button id="send" onclick="send();">Send input</button>
<button id="resize" onclick="resize();">Resize input box</button>
</div>
</div>
Edit: thanks to #SomeoneSpecial for suggesting a simplification to the scroll code!
Please try the following fiddle - https://jsfiddle.net/Hazardous/bypxg25c/. Although the fiddle is currently using jQuery to grow/resize the text area, the crux is in the flex related styles used for the messages-container and input-container classes -
.messages-container{
order:1;
flex:0.9 1 auto;
overflow-y:auto;
display:flex;
flex-direction:row;
flex-wrap:nowrap;
justify-content:flex-start;
align-items:stretch;
align-content:stretch;
}
.input-container{
order:2;
flex:0.1 0 auto;
}
The flex-shrink value is set to 1 for .messages-container and 0 for .input-container. This ensures that messages-container shrinks when there is a reallocation of size.
I've moved text-input within messages, absolute positioned it to the bottom of the container and given messages enough bottom padding to space accordingly.
Run some code to add a class to conversation, which changes the height of text-input and bottom padding of messages using a nice CSS transition animation.
The JavaScript runs a "scrollTo" function at the same time as the CSS transition is running to keep the scroll at the bottom.
When the scroll comes off the bottom again, we remove the class from conversation
Hope this helps.
https://jsfiddle.net/cnvzLfso/5/
var doScollCheck = true;
var objConv = document.querySelector('.conversation');
var objMessages = document.querySelector('.messages');
var objInput = document.querySelector('.text-input');
function scrollTo(element, to, duration) {
if (duration <= 0) {
doScollCheck = true;
return;
}
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
setTimeout(function() {
element.scrollTop = element.scrollTop + perTick;
if (element.scrollTop === to) {
doScollCheck = true;
return;
}
scrollTo(element, to, duration - 10);
}, 10);
}
function resizeInput(atBottom) {
var className = 'bigger',
hasClass;
if (objConv.classList) {
hasClass = objConv.classList.contains(className);
} else {
hasClass = new RegExp('(^| )' + className + '( |$)', 'gi').test(objConv.className);
}
if (atBottom) {
if (!hasClass) {
doScollCheck = false;
if (objConv.classList) {
objConv.classList.add(className);
} else {
objConv.className += ' ' + className;
}
scrollTo(objMessages, (objMessages.scrollHeight - objMessages.offsetHeight) + 50, 500);
}
} else {
if (hasClass) {
if (objConv.classList) {
objConv.classList.remove(className);
} else {
objConv.className = objConv.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
}
}
}
objMessages.addEventListener('scroll', function() {
if (doScollCheck) {
var isBottom = ((this.scrollHeight - this.offsetHeight) === this.scrollTop);
resizeInput(isBottom);
}
});
html,
body {
height: 100%;
width: 100%;
background: white;
}
body {
margin: 0;
padding: 0;
}
.conversation {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
position: relative;
}
.messages {
overflow-y: scroll;
padding: 10px 10px 60px 10px;
-webkit-transition: padding .5s;
-moz-transition: padding .5s;
transition: padding .5s;
}
.text-input {
padding: 10px;
-webkit-transition: height .5s;
-moz-transition: height .5s;
transition: height .5s;
position: absolute;
bottom: 0;
height: 50px;
background: white;
}
.conversation.bigger .messages {
padding-bottom: 110px;
}
.conversation.bigger .text-input {
height: 100px;
}
.text-input input {
height: 100%;
}
<div class="conversation">
<div class="messages">
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is a message content
</p>
<p>
This is the last message
</p>
<div class="text-input">
<input type="text" />
</div>
</div>
</div>
You write;
Now, consider this case:
The user scrolls to the bottom of the conversation
The .text-input, dynamically gets bigger
Wouldn't the method that dynamically sets the .text-input be the logical place to fire this.props.onResize().
To whom it may concern,
The answers above did not suffice my question.
The solution I found was to make my innerWidth and innerHeight variable constant - as the innerWidth of the browser changes on scroll to adapt for the scrollbar.
var innerWidth = window.innerWidth
var innerHeight = window.innerHeight
OR FOR REACT
this.setState({width: window.innerWidth, height: window.innerHeight})
In other words, to ignore it, you must make everything constant as if it were never scrolling. Do remember to update these on Resize / Orientation Change !
IMHO current answer is not a correct one:
1/ flex-direction: column-reverse; reverses the order of messages - I didn't want that.
2/ javascript there is also a bit hacky and obsolete
If you want to make it like a PRO use spacer-box which has properties:
flex-grow: 1;
flex-basis: 0;
and is located above messages. It pushes them down to the chat input.
When user is typing new messages and input height is growing the scrollbar moves up, but when the message is sent (input is cleared) scrollbar is back at bottom.
Check my snippet:
body {
background: #ccc;
}
.chat {
display: flex;
flex-direction: column;
width: 300px;
max-height: 300px;
max-width: 90%;
background: #fff;
}
.spacer-box {
flex-basis: 0;
flex-grow: 1;
}
.messages {
display: flex;
flex-direction: column;
overflow-y: auto;
flex-grow: 1;
padding: 24px 24px 4px;
}
.footer {
padding: 4px 24px 24px;
}
#chat-input {
width: 100%;
max-height: 100px;
overflow-y: auto;
border: 1px solid pink;
outline: none;
user-select: text;
white-space: pre-wrap;
overflow-wrap: break-word;
}
<div class="chat">
<div class="messages">
<div class="spacer-box"></div>
<div class="message">1</div>
<div class="message">2</div>
<div class="message">3</div>
<div class="message">4</div>
<div class="message">5</div>
<div class="message">6</div>
<div class="message">7</div>
<div class="message">8</div>
<div class="message">9</div>
<div class="message">10</div>
<div class="message">11</div>
<div class="message">12</div>
<div class="message">13</div>
<div class="message">14</div>
<div class="message">15</div>
<div class="message">16</div>
<div class="message">17</div>
<div class="message">18</div>
</div>
<div class="footer">
<div contenteditable role="textbox" id="chat-input"></div>
</div>
<div>
Hope I could help :)
Cheers

Add a text suffix to <input type="number">

I currently have a number of inputs like this:
<input type="number" id="milliseconds">
This input field is used to represent a value in milliseconds.
I do however have multiple number inputs which take a value in dB or percentages.
<input type="number" id="decibel">
<input type="number" id="percentages">
What I would like to do is add a type suffix to the input field to let users know what kind of value the input represents. Something like this:
(This image is edited to show what result I want to have,I hid the up and down arrows from the input type as well).
I have tried to Google this but I can't seem to find anything about it. Does anyone know if this is possible, and how you can accomplish something like this?
You can use a wrapper <div> for each input element and position the unit as a pseudo element ::after with the content of your corresponding units.
This approach works well for the absolute positioned pseudo elements will not effect the existing layouts. Nevertheless, the downside of this approach is, that you have to make sure, that the user input is not as long as the text field, otherwise the unit will be unpleasantly shown above. For a fixed user input length, it should work fine.
/* prepare wrapper element */
div {
display: inline-block;
position: relative;
}
/* position the unit to the right of the wrapper */
div::after {
position: absolute;
top: 2px;
right: .5em;
transition: all .05s ease-in-out;
}
/* move unit more to the left on hover or focus within
for arrow buttons will appear to the right of number inputs */
div:hover::after,
div:focus-within::after {
right: 1.5em;
}
/* handle Firefox (arrows always shown) */
#supports (-moz-appearance:none) {
div::after {
right: 1.5em;
}
}
/* set the unit abbreviation for each unit class */
.ms::after {
content: 'ms';
}
.db::after {
content: 'db';
}
.percent::after {
content: '%';
}
<div class="ms">
<input type="number" id="milliseconds" />
</div>
<hr />
<div class="db">
<input type="number" id="decibel" />
</div>
<hr />
<div class="percent">
<input type="number" id="percentages">
</div>
If you want to support browsers, that doesn't show these arrows at all, make use of #supports or media queries.
Another interesting approach would be to use a little of JavaScript in order to make suffix actually stick to the input text (which probably looks better):
const inputElement = document.getElementById('my-input');
const suffixElement = document.getElementById('my-suffix');
inputElement.addEventListener('input', updateSuffix);
updateSuffix();
function updateSuffix() {
const width = getTextWidth(inputElement.value, '12px arial');
suffixElement.style.left = width + 'px';
}
/**
* Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
*
* #param {String} text The text to be rendered.
* #param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
*
* #see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
*/
function getTextWidth(text, font) {
// re-use canvas object for better performance
var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
context.font = font;
var metrics = context.measureText(text);
return metrics.width;
}
#my-input-container {
display: inline-block;
position: relative;
font: 12px arial;
}
#my-input {
font: inherit;
}
#my-suffix {
position: absolute;
left: 0;
top: 3px;
color: #555;
padding-left: 5px;
font: inherit;
}
<div id="my-input-container">
<input type="number" id="my-input" value="1500">
<span id="my-suffix">ms.</span>
</div>
However, this is just a proof of concept. You will need to work on it a little further to make it production-ready, e.g. make it a reusable plugin.
Also, you will need to handle a case, where input element is getting overflowed.
If you have option to add elements to input then you can try this:
.container {
max-width: 208px; /*adjust it*/
margin: auto;
position: relative;
display: inline-block;
}
#milliseconds {
padding-right: 35px;
}
.ms {
position: absolute;
top: 0;
right: 10px;
}
<div class="container">
<input type="text" id="milliseconds">
<span class="ms">ms</span>
</div>
I have a case where the design team wants the suffix to float with the values. We are using a custom font with very uneven number widths. I came with an idea to use a ghost to follow the input width and clamp the overflow with max-width by using a wrapper element. This is still a bit work in progress and glitchy (no initial fill, etc.).
const fillBuffer = (e) => {
// Clear the buffer if input gets wiped
if (e.target.value.length === 0) {
e.target.parentElement.querySelector('.suffix span').textContent = "";
return;
}
// Using a filler char will prevent the suffix to be overwritten with the input
const extraFiller = e.target.value.length ? '1' : '';
e.target.parentElement.querySelector('.suffix span').textContent = e.target.value + extraFiller;
}
// Attach the listeners
document.querySelectorAll('input').forEach((el) => {
el.addEventListener('keydown', fillBuffer);
el.addEventListener('keyup', fillBuffer);
});
* {
font-size: 1em;
font-family: Papyrus, sans-serif;
box-sizing: border-box;
}
body {
padding: 1em;
}
.input-wrapper {
margin-bottom: 0.5em;
}
.input-wrapper.with-suffix {
position: relative;
max-width: 150px;
overflow: hidden;
}
.input-wrapper.with-suffix input {
margin: 0;
width: 100%;
outline: 0;
padding-left: 4px;
padding-right: 16px;
}
.input-wrapper.with-suffix .suffix {
position: absolute;
padding-left: 6px;
top: 2px;
pointer-events: none;
width: 100%;
}
.input-wrapper.with-suffix .suffix span {
user-select: none;
pointer-events: none;
}
.input-wrapper.with-suffix .suffix .filler {
display: inline-block;
white-space: pre; /* Allow more than two whitespaces to be rendered */
color: rgba(0, 0, 0, 0.0);
background: rgba(255, 0, 0, 0.3);
max-width: calc(100% - 16px);
}
<div class="input-wrapper with-suffix">
<input type="text" value="5000">
<div class="suffix"><span class="filler">5000</span><span>€</span></div>
</div>
<div class="input-wrapper with-suffix">
<input type="text" value="5000">
<div class="suffix"><span class="filler">5000</span><span>€</span></div>
</div>

Custom style to jQuery UI dialogs

I am trying to change jQuery UI dialog's default styles to something similar to this -
I got it to close changing some CSS in jQuery UI.
.ui-widget {
font-family: Verdana,Arial,sans-serif;
font-size: .8em;
}
.ui-widget-content {
background: #F9F9F9;
border: 1px solid #90d93f;
color: #222222;
}
.ui-dialog {
left: 0;
outline: 0 none;
padding: 0 !important;
position: absolute;
top: 0;
}
#success {
padding: 0;
margin: 0;
}
.ui-dialog .ui-dialog-content {
background: none repeat scroll 0 0 transparent;
border: 0 none;
overflow: auto;
position: relative;
padding: 0 !important;
}
.ui-widget-header {
background: #b0de78;
border: 0;
color: #fff;
font-weight: normal;
}
.ui-dialog .ui-dialog-titlebar {
padding: 0.1em .5em;
position: relative;
font-size: 1em;
}
HTML :
<div id="popup-msg">
<div id="loading">
<h2>Loading...</h2>
<h3>Please wait a few seconds.</h3>
</div>
<div id="success" title="Hurray,">
<p>User table is updated.</p>
</div>
</div>
THIS IS FIDDLE
But when I add this style its apply to all my dialogs. Can anybody tell me how can I avoid from this problem.
Thank you.
See https://jsfiddle.net/qP8DY/24/
You can add a class (such as "success-dialog" in my example) to div#success, either directly in your HTML, or in your JavaScript by adding to the dialogClass option, as I've done.
$('#success').dialog({
height: 50,
width: 350,
modal: true,
resizable: true,
dialogClass: 'no-close success-dialog'
});
Then just add the success-dialog class to your CSS rules as appropriate. To indicate an element with two (or more) classes applied to it, just write them all together, with no spaces in between. For example:
.ui-dialog.success-dialog {
font-family: Verdana,Arial,sans-serif;
font-size: .8em;
}
You can specify a custom class to the top element of the dialog via the option dialogClass
$("#success").dialog({
...
dialogClass:"myClass",
...
});
Then you can target this class in CSS via .myClass.ui-dialog.
The solution only solves part of the problem, it may let you style the container and contents but doesn't let you change the titlebar. I developed a workaround of sorts but adding an id to the dialog div, then using jQuery .prev to change the style of the div which is the previous sibling of the dialog's div. This works because when jQueryUI creates the dialog, your original div becomes a sibling of the new container, but the title div is a the immediately previous sibling to your original div but neither the container not the title div has an id to simplify selecting the div.
HTML
<button id="dialog1" class="btn btn-danger">Warning</button>
<div title="Nothing here, really" id="nonmodal1">
Nothing here
</div>
You can use CSS to style the main section of the dialog but not the title
.custom-ui-widget-header-warning {
background: #EBCCCC;
font-size: 1em;
}
You need some JS to style the title
$(function() {
$("#nonmodal1").dialog({
minWidth: 400,
minHeight: 'auto',
autoOpen: false,
dialogClass: 'custom-ui-widget-header-warning',
position: {
my: 'center',
at: 'left'
}
});
$("#dialog1").click(function() {
if ($("#nonmodal1").dialog("isOpen") === true) {
$("#nonmodal1").dialog("close");
} else {
$("#nonmodal1").dialog("open").prev().css('background','#D9534F');
}
});
});
The example only shows simple styling (background) but you can make it as complex as you wish.
You can see it in action here:
https://codepen.io/chris-hore/pen/OVMPay

Resources