AngularJS ng-class after :active or :focus - css

I have a form I am trying to create using CSS to achieve a halfway "material" feel. I achieved a lot of the animations by ditching the stock bootstrap forms entirely and rewriting them to get the maximum amount of flexibility.
EDIT: Forgot to link Codepen - http://codepen.io/h3xc0ntr0l/pen/ONwdLm
Essentially, the "form groups" are set to position:relative and used to position the input and a couple pseudo elements absolutely, yada yada. I am using angular and am not able to incorporate jquery into the project.
my problem is as follows
<div class="-form-group">
<input type="email" class="-form-input" ng-class='{"content":"user.email"}' ng-model="user.email"/>
<span class="in-email"></span>
</div>
this does not have the behavior i need. I guess if I have "ng-model", then whatever is in there is going to evaluate to true.
I also tried the following with scss:
.-form-input{
border: none;
box-shadow: none;
border-radius: 0;
font-size: 1rem;
background: none;
outline: none;
width: 100%;
margin-top: 2em;
position: relative;
z-index:4;
&:active, &:focus{
.in-email &{ //
&:before{
top: -50%;
color: transparent;
border-bottom: transparent;
}
}
}
}
the effects are achieved via
.in-email, .in-pwd{
&:before{
position: absolute;
top: 50%;
left: 0%;
width: 100%;
z-index:3;
color: black;
transition: 500ms ease all;
border-bottom: 1.5px solid rgba(128,128,128, .5);
}
}
I can not think of anything else that would prevent the span from coming back down after i leave the hover regardless of whether or not there is any content. does anyone have any tips?
(function(){
angular.module('app').controller([
'$scope', function($scope){
$scope.user = undefined;
}
]);
})();
form {
width: 100%;
padding: 1em;
border: .25px solid #e9e9e9;
box-shadow: 0 1rem 3rem 0 rgba(0, 0, 0, 0.33);
height: 20rem;
margin: 0 auto;
}
form .-form-group {
position: relative;
width: 100%;
height: auto;
transition: 500ms ease;
margin: 0 1em 2em 0;
}
form .-form-group .-form-input {
border: none;
box-shadow: none;
border-radius: 0;
font-size: 1rem;
background: none;
outline: none;
width: 100%;
margin-top: 2em;
position: relative;
z-index: 4;
}
.in-email form .-form-group .-form-input:active:before, .in-email form .-form-group .-form-input:focus:before {
top: -50%;
color: transparent;
border-bottom: transparent;
}
form .-form-group input:-webkit-autofill {
background-color: #e9e9e9 !important;
}
form .-form-group:after {
content: "";
display: block;
transition: 250ms 500ms ease all;
border-bottom: 1.5px solid #288690;
width: 0;
}
form .-form-group:hover:after, form .-form-group:focus:after, form .-form-group:active:after {
content: "";
width: 100%;
top: 90%;
}
form .-form-group:hover .in-email:before, form .-form-group:hover .in-pwd:before, form .-form-group:focus .in-email:before, form .-form-group:focus .in-pwd:before, form .-form-group:active .in-email:before, form .-form-group:active .in-pwd:before {
top: -50%;
color: transparent;
border-bottom: transparent;
}
form .button {
border-radius: 1px;
border: none;
}
form .in-email:before, form .in-pwd:before {
position: absolute;
top: 50%;
left: 0%;
width: 100%;
z-index: 3;
color: black;
transition: 500ms ease all;
border-bottom: 1.5px solid rgba(128, 128, 128, 0.5);
}
.content:before {
content: "" !important;
}
.in-email:before {
content: "Email Address";
}
.in-pwd:before {
content: "Password";
}
.nav, .pagination, .carousel, .panel-title a {
cursor: pointer;
}
#ui-root {
margin-top: 5rem;
padding: 1rem;
}
.ui-container {
position: relative;
width: 100%;
padding: 0 10% 0 10%;
}
.button {
background-color: #288690 !important;
}
<link rel="stylesheet" href="http://getbootstrap.com/dist/css/bootstrap.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<div class="container">
<div class="ui-container">
<div class="row" id="ui-root">
<div class="col-sm-12 col-md-4 col-md-offset-4">
<form autocomplete="off" class="text-center">
<!-- chrome autcomplete -->
<div class="-form-group">
<input type="email" class="-form-input" ng-class='{"content": "user.email"}' ng-model="user.email"/>
<span class="in-email"></span>
</div>
<div class="-form-group">
<input type="password" class="-form-input" ng-class='{"content": "user.password"}' ng-model="user.password" />
<span ng-class='{"content": "user.password"}' class="in-pwd"></span>
</div>
<button class="btn btn-primary button">Login</button>
</form>
</div>
</div>
</div>
</div>

Related

Text input - can't align text top or bottom, only center

folks! I'm trying to align the text inside a text form input to be next to the line at the bottom, but it doesn't quite concede, insisting on being center aligned.
I've put some vertical-align: bottom on different elements, but it didn't work (it's on the code below).
Here is the codepen: https://codepen.io/ironsand-sou-eu/pen/zYEmEdw
HTML:
<div class="form-input field">
<input type="text" name="my_input" id="my_input" value="I'd love to be a little closer to the line below! Can you help me?">
<label for="my_input" data-title="Just some label"></label>
</div>
CSS:
.form-input {
width: 100%;
background-color: transparent;
border-bottom: 1px green solid;
border-top: none;
border-right: none;
border-left: none;
}
.form-input::before {
content: '';
position: absolute;
background-color: green;
left: 0;
bottom: 0;
width: 0;
height: 2px;
transition: ease-out 300ms;
}
.form-input:hover::before {
width: 100%;
}
.form-input:focus-within::before {
width: 100%;
}
.form-input input {
border: none;
width: 100%;
}
.form-input input:focus-visible {
outline: none;
}
.field {
position: relative;
margin-bottom: 15px;
vertical-align: bottom;
}
.field label::before {
content: attr(title);
position: absolute;
top: 0;
left: 15px;
line-height: 40px;
font-size: 14px;
color: #777;
transition: 300ms all;
}
.field input {
width: 100%;
line-height: 40px;
padding: 0 8px;
box-sizing: border-box;
font-size: 14px;
color: green;
vertical-align: bottom;
}
Place this at the bottom of the CSS section:
input[type=text] {
height: 15px;
}

Floating labels - label above input field

I'm working on an existing form, where I want to introduce floating labels.
A lot of the solutions I have seen on stack overflow are great, but require the label tag, to sit directly underneath the <input> tag. For example here.
On the form I'm working on though, my label tag, sits above the <input> tag. And the input tag, sits in a seperate div. (I am not allowed to move these tags around - please don't ask, restriction of the application!).
Is there anyway, I can achieve floating CSS labels, with this structure?
.test-field {
clear: both;
margin-bottom: 20px;
position: relative;
}
.test-field__input {
font-size: 0.875em;
line-height: 1;
-moz-appearance: none;
-webkit-appearance: none;
background-color: #f5f5f5;
border: 2px solid #eee;
border-radius: 4px;
color: grey;
height: calc((40 / 14) * 1em);
line-height: 1;
outline: 0;
padding: 0 8px;
vertical-align: top;
width: 100%;
}
/* // FOCUS */
.test-field__input:focus,
.test-field__input ~ input:checked:focus {
border-color: #5d7199;
}
/* // DISABLED */
.test-field--disabled .test-field__input {
background-color: #e8e8e3;
cursor: not-allowed;
}
.test-field--disabled .test-field__flag, .test-field--disabled .test-field__label {
color: #d0d0cb;
}
/* // ERROR */
.test-field--error .test-field__input, .test-field--error .test-field__selection .atc-field__input {
border-color: #ff4436;
color: #ff4436;
}
/* // FLOATING LABEL */
.test-field--floating .test-field-input {
position: relative;
margin-bottom: 1.5rem;
}
.test-field__label {
position: absolute;
top: 0;
padding: 7px 0 0 13px;
transition: all 200ms;
opacity: 0.5;
}
.test-field__input:focus + .test-field__label,
.test-field--floating .test-field__input:valid + .test-field__label {
font-size: 75%;
transform: translate3d(0, -100%, 0);
opacity: 1;
}
<div class="test-field test-field--floating">
<label for="a" class="test-field__label">Input label</label>
<input class="test-field__input" id="b" type="text" value="" required>
</div>
This seemed to be a good way to replicate floating labels, with a similar DOM structure:
const floatField = document.querySelectorAll('.ej-form-field-input-textbox');
const floatContainer = document.querySelectorAll('.ej-form-field');
for (let i = 0; i < floatField.length; i++) {
floatField[i].addEventListener('focus', () => {
floatContainer[i].classList.add('active');
});
};
for (let i = 0; i < floatField.length; i++) {
floatField[i].addEventListener('blur', () => {
floatContainer[i].classList.remove('active');
});
};
.ej-form-field {
border: solid 1px #ccc;
padding: 0 8px;
position: relative;
}
.ej-form-field input {
border: 1px solid red;
font-size: 16px;
outline: 0;
height: 30px;
/* padding: 16px 0 10px; */
}
label {
font-size: 16px;
position: absolute;
transform-origin: top left;
transform: translate(0, 16px) scale(1);
transition: all .1s ease-in-out;
height: 40px;
}
.ej-form-field.active label {
transform: translate(0, -6px) scale(.95);
color: red;
margin-left: 10px;
background-color: #fff;
border: 1px solid green;
height: 20px;
}
<div id="floatContainer" class="ej-form-field">
<label for="floatField">First name</label>
<div>
<input id="floatField" class="ej-form-field-input-textbox" type="text">
</div>
</div>
<div id="floatContainer" class="ej-form-field">
<label for="floatField">Last name</label>
<div>
<input id="floatField" class="ej-form-field-input-textbox" type="text">
</div>
</div>

Button not laid out against top of relatively positioned container in Firefox

I'm building a toggle switch and the head (button) isn't positioned all the way to the top as I'd expect it to be in Firefox. Works fine in Chrome, so maybe has something to do with default browser styles?
Edit: I know how to make it work, I want to know why it happens.
codepen https://codepen.io/warhammered_cat/pen/qBZYZVy
const toggleSwitch = document.querySelector('.toggle-switch')
const toggleSwitchHead = document.querySelector('.head')
function handleToggle(e) {
toggleSwitch.classList.toggle('active')
}
toggleSwitchHead.addEventListener('click', handleToggle)
* {
box-sizing: border-box;
}
document, body {
margin: 0;
padding: 0;
}
.head {
width: 1.25rem;
height: 1.25rem;
border: 0.125rem solid gray;
border-radius: 50%;
background-color: white;
cursor: pointer;
transition: all 0.4s;
outline: none;
box-shadow: none;
}
.rail {
height: 0.75rem;
width: 100%;
background-color: gray;
border: 0.125rem solid gray;
position: absolute;
top: 0.25rem;
z-index: -1;
border-radius: 0.3rem;
transition: all 0.4s;
}
.toggle-switch {
position: relative;
height: 1.25rem;
width: 2rem;
}
.toggle-switch.active > .head {
background-color: #F7941E;
border-color: #F7841E;
transform: translateX(1rem);
}
.toggle-switch.active > .rail {
border: 0.125rem solid #F7941E;
background-color: white;
}
<div class='toggle-switch'>
<button class='head'></button>
<div class='rail'></div>
</div>
The <button> element is what is specifically being rendered differently in Firefox and Chrome.
If you change the <button> to a <div> the problem fixes itself.
The reason is that the button element is not a block element by default. You have to explicitly set the button to be a block element to get the desired behavior.
.head {
...
display: block;
...
}
try this instead,
Add display:inline-flex; to head class
.head{
display:inline-flex;
}
Click below to see codepen demo
Result :
const toggleSwitch = document.querySelector('.toggle-switch')
const toggleSwitchHead = document.querySelector('.head')
function handleToggle(e) {
toggleSwitch.classList.toggle('active')
}
toggleSwitchHead.addEventListener('click', handleToggle)
* {
box-sizing: border-box;
}
document, body {
margin: 0;
padding: 0;
}
.head {
width: 1.25rem;
height: 1.25rem;
border: 0.125rem solid gray;
border-radius: 50%;
background-color: white;
cursor: pointer;
transition: all 0.4s;
outline: none;
box-shadow: none;
display:inline-flex;
}
.rail {
height: 0.75rem;
width: 100%;
background-color: gray;
border: 0.125rem solid gray;
position: absolute;
top: 0.25rem;
z-index: -1;
border-radius: 0.3rem;
transition: all 0.4s;
}
.toggle-switch {
position: relative;
height: 1.25rem;
width: 2rem;
}
.toggle-switch.active > .head {
background-color: #F7941E;
border-color: #F7841E;
transform: translateX(1rem);
}
.toggle-switch.active > .rail {
border: 0.125rem solid #F7941E;
background-color: white;
}
<div class='toggle-switch'>
<button class='head'></button>
<div class='rail'></div>
</div>

How to add an image to the back of a custom checkbox

I found a really clean looking custom checkbox on codepen and just updated a project to use it. Right now I've got the background colors different for the different sections of my form, but I'd like to just make background an icon rather than just a solid color
The commented out stuff doesn't work
.label-switch {
display: inline-block;
position: relative;
}
.label-switch::before,
.label-switch::after {
content: "";
display: inline-block;
cursor: pointer;
transition: all 0.5s;
}
.label-switch::before {
width: 3em;
height: 1em;
border: 1px solid #757575;
border-radius: 4em;
background: #888888;
}
.label-switch::after {
position: absolute;
left: 0;
top: -20%;
width: 1.5em;
height: 1.5em;
border: 1px solid #757575;
border-radius: 4em;
background: #ffffff;
}
.input-switch:checked~.label-switch::before {
background: #00a900;
border-color: #008e00;
}
.input-switch:checked~.label-switch::after {
left: unset;
right: 0;
background: #00ce00;
/*background-image:(url(http://pngimg.com/uploads/pokeball/pokeball_PNG8.png);*/
/*background: url(http://pngimg.com/uploads/pokeball/pokeball_PNG8.png);*/
border-color: #009a00;
}
<input class='input-switch' type="checkbox" id="demo" />
<label class="label-switch" for="demo"></label>
<span class="info-text"></span>
Everything you did was correct it's just the background image needed to have a background-position and background-size set if you toggle the checkbox in my snippet you should see the background pattern as you intended it to work.
.label-switch{
display: inline-block;
position: relative;
}
.label-switch::before, .label-switch::after{
content: "";
display: inline-block;
cursor: pointer;
transition: all 0.5s;
}
.label-switch::before {
width: 3em;
height: 1em;
border: 1px solid #757575;
border-radius: 4em;
background: #888888;
}
.label-switch::after {
position: absolute;
left: 0;
top: -20%;
width: 1.5em;
height: 1.5em;
border: 1px solid #757575;
border-radius: 4em;
background: #ffffff;
}
.input-switch:checked ~ .label-switch::before {
background: #00a900;
border-color: #008e00;
}
.input-switch:checked ~ .label-switch::after {
left: unset;
right: 0;
background: #00ce00;
background-image:url(http://pngimg.com/uploads/pokeball/pokeball_PNG8.png);
background-size:contain;
background-position:center;
border-color: #009a00;
}
<input class='input-switch' type="checkbox" id="demo"/>
<label class="label-switch" for="demo"></label>
<span class="info-text"></span>

HTML5 slider bar's thumb can't cover the track

I made a slider bar with html5 & css, like this.
function showValue(value) {
document.getElementById("range").innerHTML = value;
}
.c-zoombar {
-webkit-appearance: none;
background: none;
outline: none;
overflow: hidden;
width: 200px;
height: 20px;
}
.c-zoombar::-webkit-slider-thumb {
-webkit-appearance: none;
background: #5e6fd9;
border: 1px solid #fff;
border-radius: 50%;
height: 12px;
position: relative;
top: -5.5px;
transition: .2s;
width: 12px;
}
.c-zoombar::-webkit-slider-runnable-track {
background: transparent;
border: 1px solid #000;
border-radius: 2px;
cursor: pointer;
height: 3px;
width: 100%;
}
.c-zoombar:active::-webkit-slider-thumb {
height: 16px;
top: -8px;
width: 16px;
}
.c-zoombar::-webkit-slider-thumb:hover {
height: 16px;
top: -8px;
width: 16px;
}
<div>
<input type="range" value="0" class="c-zoombar" onInput="showValue(this.value)" />
</div>
<div>
<span id="range">0</span>
</div>
However, when I scroll the thumb to the most right/left, the thumb can't totally cover the track, as you can see in the following image.
What should I modify to make the thumb be able to cover the track when scrolling to the most right/left? Thank you.
I found the transform: scale() could do the part of trick (also scale transitioned more smoothly then width/height). is that 12px size is mandatory?
function showValue(value) {
document.getElementById("range").innerHTML = value;
}
.c-zoombar {
-webkit-appearance: none;
background: none;
outline: none;
overflow: visible;
width: 200px;
height: 20px;
}
.c-zoombar::-webkit-slider-thumb {
-webkit-appearance: none;
background: #5e6fd9;
border: 1px solid #fff;
border-radius: 50%;
height: 12px;
position: relative;
top: -5.5px;
transition: .2s;
width: 12px;
transform: scale(1.33);
}
.c-zoombar::-webkit-slider-runnable-track {
background: transparent;
border: 1px solid #000;
border-radius: 2px;
cursor: pointer;
height: 3px;
width: 100%;
}
.c-zoombar:active::-webkit-slider-thumb,
.c-zoombar::-webkit-slider-thumb:hover {
transform: scale(1.66);
}
<div class='wrap'>
<input type="range" value="0" class="c-zoombar" onInput="showValue(this.value)" />
</div>
<div>
<span id="range">0</span>
</div>

Resources