User-action pseudo class with a negating pseudo class - html

Is it possible to place a negating pseudo class with a user-action pseudo class?
For example:
a:hover:not(href) {
color: blue;
}
// or //
a:not(href):hover {
color: blue;
}
// or //
a:not(href) {
&:hover {
color: blue:
}
}
Here, the hover state of a link would turn the color blue if it did not have a "href".
I am trying to use this with "input[type="radio"]" and change the hover state of the radio if it is not checked (:checked). I know this kind of sounds like an if else statement with CSS, and I guess that's what I am trying to slightly accomplish without having to use js.

This may not help (always a good start to an answer), but if you control the HTML, then there's definitely a way. I tried what you'd expect the code to be...
input[type="radio"]:not(:checked):hover {
/* styles */
}
...but that didn't work. It was flickering and rubbish.
So, the only way I could think of was to have a relatively positioned container, and then absolutely position two elements inside it, a label and the input, and then have the input styles changed when you hover on the label. Using z-index we can bring the label above the input box. Then, because of the for attribute, we can make sure that the checkbox is still checked when the label is clicked.
The style I've changed on hover is the margin-top, which will pull the radio button up.
HTML
<span>
<label for="radio1">Click me</label>
<input id="radio1" type="radio" />
</span>
<span>
<label for="radio2">Click me</label>
<input id="radio2" type="radio" checked />
</span>
CSS
span {
position: relative;
display: inline-block;
min-width: 13px;
}
label, input {
position: absolute;
top: 0;
left: 0;
display: inline-block;
margin: 0;
}
label {
z-index: 2;
text-indent: -999em;
width: 13px;
height: 13px;
}
input {
z-index: 1;
}
label:hover + input[type="radio"]:not(:checked) {
margin-top: -10px;
}
Demo
http://jsbin.com/ifArIn/3/edit

Related

Custom checkbox wont toggle when click and drag on label

I have a problem with my custom checkbox.
If you click on a checkbox element, move the mouse cursor and then release the click inside the checkbox area, the checkbox is checked.
However, if you do the same on a custom checkbox (here, a div inside a label), the checkbox isn't checked.
It's a problem because if you want to quickly check a checkbox, you may move the mouse after pressing the button of the mouse and before releasing it, thus not toggling the checkbox.
The user is obligated to click without moving the mouse.
I know I can use JS to emulate a checkbox with a div, but I want the HTML to be semantically correct, so: Is it possible to fix it without js?
Here's the code :
/* 1. Hide the checkbox */
.hidden {
/* https://zellwk.com/blog/hide-content-accessibly/ */
border: 0;
clip: rect(0, 0, 0, 0);
height: auto;
margin: 0;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
white-space: nowrap;
}
/* 2. Use a label to retrieve the click event */
label {
/* not used directly to prevent the bug in firefox https://bugzilla.mozilla.org/show_bug.cgi?id=608180 */
pointer-events: none;
display: inline-flex;
}
label > input {
/*usefull for testing only*/
pointer-events : all;
}
label > .customCheckbox {
cursor: pointer;
display: inline-flex;
justify-content: center;
align-items: center;
position: relative;
--size:200px;
width: var(--size);
height: var(--size);
font-size: calc(var(--size)/2);
pointer-events: all;
}
label > .customCheckbox::selection{
/* prevent highliting the text within the custom checkbox */
background: none;
}
label > .customCheckbox:after {
z-index: -1;
content: "✔";
display: inline-flex;
justify-content: center;
align-items: center;
position: absolute;
width: 100%;
height: 100%;
box-sizing: border-box;
border-radius: calc(var(--size)/4);
border: solid black calc(var(--size)/10);
}
label > input:not(:checked) + div.customCheckbox:after {
background:#0000;
content: "\a0";
}
<input type="checkbox"/>
<label >
<input type="checkbox" class="hidden"/>
<div class="customCheckbox"></div>
</label >
I need the checkbox to be inside the label because I can't use the "for" attribute.
Thanks a lot for your help!
EDIT: for those wondering, here's the js solution (not ideal but since I can't do it in CSS, it's better than nothing) :
let checkboxes = document.getElementsByClassName("customCheckbox");
for(let i=0; i<checkboxes.length; i++){
checkboxes[i].addEventListener('mouseover', (e)=>{handleMouseOverCheckbox(e)})
checkboxes[i].addEventListener('mousedown', (e)=>{handleMouseOverCheckbox(e)})
}
function handleMouseOverCheckbox(e) {
e.srcElement.previousElementSibling.disabled = "true";
if (e.buttons == 1) {
e.srcElement.previousElementSibling.checked= !e.srcElement.previousElementSibling.checked;
}}
EDIT 2 : Here's the best solution I could come up with, thanks to
#zer00ne
codepen.io/DesignThinkerer/pen/bGVBLjM
A checkbox within a label is no problem. The problem arises when that checkbox is altered for the sake of accessibility instead of complete removal using display: none. When an interactive element like an input or button exists in the DOM, it will still be a factor no matter how its hidden unless display: none is applied.
In the Original Post the checkbox is almost impossible to click due to its 0px height and 1px width and yet when the div is clicked, the checkbox is clicked... sometimes not. Normally if the label was able to detect a click, that click would trigger a click event to the nested checkbox as well. In the OP code that's not happening because the label has pointer-events: none.
So the div is getting clicked and by some magical miracle this gains features that would not normally be attributed to it? Divs are not interactive they cannot affect elements that are not nested within themselves (i.e. like the checkbox that sits before the div). Nope, the div is useless, its the checkbox itself that's getting clicked due to the fact it is the only element within the inert label that gains focus by default. Gaining focus on an input doesn't necessarily guarantee a click event -- matter of fact a focus event selects an element and a click event sets an element as active. So what happens when a user double-clicks or moves the mouse quickly before the next click clears a label? Undesirable behavior as described in OP.
In the following demo, the checkboxes are hidden as per OP (also set width and height to 0) and removed pointer-events: none from the label and added it to the checkboxes. In this setup the label gains focus and click events and the click event will trigger the checkbox. The checkbox having been isolated from any extra clicks due to pointer-events: none and z-index: -1 should behave as expected.
As proof of concept I have added some JavaScript to demonstrate said code stability. The two event handlers are for demonstration purposes. The JS does not facilitate, stabilize, or modify performance of the HTML/CSS behavior.
On any change event on a checkbox (via label) will trigger function changeHandler() to gather all the values of the checked checkboxes and display them in an output.
If there's a checkmark in a box and there's a value displayed that corresponds to said checked checkbox, then it successfully passes as valid behavior.
Clicking button.show will trigger function clickHandler() to toggle the .reveal class to each checkbox.
While clicking rapidly observe that the revealed checkboxes are checked and its corresponding custom label is checked as well. Also notice that the value should also be displayed as well.
BTW
"....target doesn't work in IE IIRC"
event.target is the standard property to use in every modern browser. event.srcElement is a deprecated property used by IE which is almost entirely unsupported.
pointer-events: all assigned to input and .customCheckbox
The value all applies to SVG only. Only the values of none and auto are relevant to HTML. auto is default.
Demo
I cannot reproduce the described behavior except in the code provided in OP. If you can reproduce that behavior on my demo, please record a short video of it and post that and the machine/device, OS, and browsers (I will assume everything is reasonably up to date).
const main = document.forms.main;
main.onchange = checkHandler;
function checkHandler(e) {
const fc = this.elements;
const chx = [...fc.hidden];
const ui = e.target;
if (ui.matches('.hidden')) {
let text = chx.flatMap(c => c.checked ? [c.value] : []);
fc.view.value = '';
fc.view.value = text.join(', ');
}
}
main.onclick = clickHandler
function clickHandler(e) {
const fc = this.elements;
const chx = [...fc.hidden];
const ui = e.target;
if (ui.matches('button.show')) {
chx.forEach(c => c.classList.toggle('reveal'));
}
}
:root,
body {
--size: 10rem;
font: 400 small-caps 2vw/1.5 Times;
width: 100%;
height: 100%;
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
font: inherit;
}
.display {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
width: max-content;
max-height: min-content;
margin: 10px;
border: calc(var(--size) / 20) solid #000;
border-radius: 24px;
}
.view {
display: inline-block;
min-width: 35ch;
font-size: 1.5rem;
height: 1.5rem;
line-height: 1;
}
.show {
display: inline-block;
width: 12ch;
padding: 1px 3px;
margin: 4px;
border: 2px solid #000;
border-radius: 8px;
background: none;
text-align: center;
font-size: 1.25rem;
cursor: pointer;
}
.mask {
position: relative;
z-index: 2;
display: block;
width: var(--size);
height: var(--size);
padding: 0;
margin: 0 5px;
border: solid black calc(var(--size) / 10);
border-radius: calc(var(--size) / 4);
font-size: calc(var(--size) * 0.8);
background: none;
cursor: pointer;
}
.icon {
position: absolute;
z-index: 1;
top: -1.5rem;
right: 1rem;
display: inline-block;
margin: 0;
padding: 0;
border: 0;
}
.hidden {
position: relative;
z-index: -1;
display: inline-block;
width: 0;
height: 0;
margin: 0;
padding: 0;
border: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
pointer-events: none;
opacity: 0;
}
.reveal {
z-index: 0;
top: -24px;
left: 4px;
width: 1px;
height: 1px;
opacity: 1;
}
.icon::after {
content: attr(data-blank);
}
.hidden:checked+.icon::after {
content: attr(data-check);
}
<!DOCTYPE html>
<html>
<head lang='en'>
<meta charset='utf-8'>
<style></style>
</head>
<body>
<form name='main'>
<fieldset name='display' class='display'>
<output name='view' class='view'></output>
<button name='show' class='show' type='button'>Show</button>
</fieldset>
<fieldset name='display' class='display'>
<label name='mask' class='mask'>
<input name='hidden' class="hidden" type="checkbox" value='Check I'>
<fieldset name='icon' class='icon' data-check='✔' data-blank=' '></fieldset>
</label>
<label name='mask' class='mask'>
<input name='hidden' class="hidden" type="checkbox" value='Check II'>
<fieldset name='icon' class='icon' data-check='✔' data-blank=' '></fieldset>
</label>
<label name='mask' class='mask'>
<input name='hidden' class="hidden" type="checkbox" value='Check III'>
<fieldset name='icon' class='icon' data-check='✔' data-blank=' '></fieldset>
</label>
<label name='mask' class='mask'>
<input name='hidden' class="hidden" type="checkbox" value='Check IV'>
<fieldset name='icon' class='icon' data-check='✔' data-blank=' '></fieldset>
</label>
</fieldset>
</form>
<script></script>
</body>
</html>

Tab custom file upload button

I've created my own custom file upload button by creating a label and hiding the input element with css. This all works fine, but the problem is I can't use the button by tabbing and enter. I tried adding tabindex=0 to the label. I could then tab to the element ok but there was no action when clicking enter as it is only a label.
Here is the HTML code
<label class="custom-file-upload>
<input type="file">
Choose file
</label>
and css to hide the default file upload button
input[type="file"] {
display: none;
}
Any help is much appreciated.
This can all be achieved with CSS on modern browsers with the added benefit that:
there is no reliance on JavaScript
there is no need for a tabindex
it activates with space or enter, both of which are expected behaviours.
The key is to make the input visually hidden (using the .visually-hidden class) but still focusable and then use the + to link the label (without wrapping the input in the label).
The key part of the example below is [type="file"]:focus + label
This lets you change the label styling when the input is selected (it is important that the <label> appears immediately after the <input> in the DOM in order for this to work).
I also included the syntax for applying a ::before styling on hover and focus for completeness.
Example (not a production ready solution)
The example given below was a quick and dirty way of demonstrating how to achieve your goal, it has a couple of accessibility issues that need addressing before putting it into production:-
you shouldn't use the same styling for hover and focus -> hover you should change colour and show the icon, focus add a border and show the icon
instead of using a font for the icon you should use an SVG as fonts may break if someone overrides them (i.e. if they have a preferred font due to dyslexia).
make sure that you disable animation of the icon entering if people have indicated they prefer reduced movement by using the prefers-reduced-motion: reduce media query https://developer.mozilla.org/en-US/docs/Web/CSS/#media/prefers-reduced-motion
Also make sure you associate the label with the input using for="inputName" on the label and id="inputName" on the input.
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap;
}
[type="file"] + label {
background: #f15d22;
border: none;
border-radius: 5px;
color: #fff;
cursor: pointer;
display: inline-block;
font-size: inherit;
font-weight: 600;
margin-bottom: 1rem;
outline: none;
padding: 1rem 50px;
position: relative;
transition: all 0.3s;
vertical-align: middle;
background-color: #99c793;
border-radius: 50px;
overflow: hidden;
}
[type="file"] + label::before {
color: #fff;
content: "\f382";
font-family: "Font Awesome 5 Pro";
font-size: 100%;
height: 100%;
right: 130%;
line-height: 3.3;
position: absolute;
top: 0px;
transition: all 0.3s;
}
[type="file"]:hover + label,
[type="file"]:focus + label{
background-color: #497f42;
}
[type="file"]:hover + label::before,
[type="file"]:focus + label::before {
right: 75%;
}
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.2.0/css/all.css" />
<input type="file" id="inputName" class="visually-hidden"/>
<label for="inputName">upload</label>
You can rewrite your code something in this manner
<input id="file-upload" type="file">
<label for="file-upload" class="custom-file-upload>Choose file</label>
CSS for input and change css for label accordingly using sibling selector
input[type="file"] {
opacity: 0;
}
With labels you need to trigger click on keyboard events for enter
<label for ="file-upload1" tabindex="0" class="custom-file-upload">
<input type="file" id="file-upload"/> Choose file
</label>
CSS
input[type="file"]{
display:none;
}
JQuery Code
$('.custom-file-upload').on('keyup',function(event){
if (event.keyCode === 13) {
$('#file-upload').trigger('click');
}
})
I may have a little hack that can help. You can use the focus-within attribute on your parent element that holds your file input and style it with this
parent:focus-within {
border: 1px solid blue;
background: yellow;
}

Personalize "Radio" button in a HTML from

Well, I can change the size of "Radio" using CSS but I cant quit the border and change the background color.
Here is my code:
<input type="radio" class="textColoPgE1" id="textColoPgE" name="textColoPgE" value="col1">
And the CSS:
.textColoPgE1
{
background-color: blue;
width: 20px;
height: 20px;
border: none;
}
How to personalize my "Radio" buttons? I hope you have a solution.
Thank you
You need to make a fake radio button and hide the (browser) default one to make it work. See the example below. First it's a blue button, but after it's been clicked (and checked), it's red.
The label:before will be the container where your fake radio button will show up.
/* Hide the radio button */
input[type=radio] {
display: none;
}
/* We style the label */
.textColoPgE1-label {
display: inline-block;
cursor: pointer;
position: relative;
padding-left: 25px;
margin-right: 15px;
}
.textColoPgE1-label:before {
content: "";
display: block;
width: 20px;
height: 20px;
top: 0;
position: absolute;
background-color: blue;
left: 0;
border-radius: 50%;
}
/* We style the checked item */
.textColoPgE1:checked + .textColoPgE1-label:before {
background-color: red;
}
<input type="radio" class="textColoPgE1" id="textColoPgE" name="textColoPgE" value="col1">
<label for="textColoPgE" class="textColoPgE1-label">Radio button</label>
You have here a great example of what you need to do to make your own radio button style:
http: //codepen.io/mitchmc/pen/pebIx
Basically, you need to turn of the button and style the label.
I searched for solutions for the same issue and found this very clear and helpful explanation: http://code.stephenmorley.org/html-and-css/styling-checkboxes-and-radio-buttons/

How to override bootstrap checkbox style

I bought a bootstrap template, the style sheet file, has this code:
input[type=checkbox],
input[type=radio] {
opacity: 0;
position: absolute;
left: -9999px;
z-index: 12;
width: 18px;
height: 18px;
cursor: pointer;
}
I have a html table that has a cell with a checkbox, that is not showing up, with chrome inspector, I modified turn off the styling properties,
My question Is there any way that I could tell my code not to apply that style in the checkbox that is inside the table cell??
thanks
Alberto
yes, specifically call that check box add a class to the checkbox something like this <input type="checkbox" class="unique-class"/> then in your css add the style to just that checkbox with something like this
input.unique-class[type=checkbox],
input.unique-class[type=radio] {
/*stuff here*/
}
input[type="radio"], input[type="checkbox"] {
/*stuff here*/
cursor:pointer;
}

Hide the browse button on a input type=file

Is there a way to hide the browse button and only leave the text box that works in all browsers?
I have tried setting the margins but they show up different in each browser
No, what you can do is a (ugly) workaround, but largely used
Create a normal input and a image
Create file input with opacity 0
When the user click on the image, you simulate a click on the file input
When file input change, you pass it's value to the normal input (so user can see the path)
Here you can see a full explanation, along with code:
http://www.quirksmode.org/dom/inputfile.html
You may just without making the element hidden, simply make it transparent by making its opacity to 0.
Making the input file hidden will make it STOP working. So DON'T DO THAT..
Here you can find an example for a transparent Browse operation;
.dropZoneOverlay, .FileUpload {
width: 283px;
height: 71px;
}
.dropZoneOverlay {
border: dotted 1px;
font-family: cursive;
color: #7066fb;
position: absolute;
top: 0px;
text-align: center;
}
.FileUpload {
opacity: 0;
position: relative;
z-index: 1;
}
<div class="dropZoneContainer">
<input type="file" id="drop_zone" class="FileUpload" accept=".jpg,.png,.gif" onchange="handleFileSelect(this) " />
<div class="dropZoneOverlay">Drag and drop your image <br />or<br />Click to add</div>
</div>
I find a good way of achieving this at Remove browse button from input=file.
The rationale behind this solution is that it creates a transparent input=file control and creates an layer visible to the user below the file control. The z-index of the input=file will be higher than the layer.
With this, it appears that the layer is the file control itself. But actually when you clicks on it, the input=file is the one clicked and the dialog for choosing file will appear.
Below code is very useful to hide default browse button and use custom instead:
(function($) {
$('input[type="file"]').bind('change', function() {
$("#img_text").html($('input[type="file"]').val());
});
})(jQuery)
.file-input-wrapper {
height: 30px;
margin: 2px;
overflow: hidden;
position: relative;
width: 118px;
background-color: #fff;
cursor: pointer;
}
.file-input-wrapper>input[type="file"] {
font-size: 40px;
position: absolute;
top: 0;
right: 0;
opacity: 0;
cursor: pointer;
}
.file-input-wrapper>.btn-file-input {
background-color: #494949;
border-radius: 4px;
color: #fff;
display: inline-block;
height: 34px;
margin: 0 0 0 -1px;
padding-left: 0;
width: 121px;
cursor: pointer;
}
.file-input-wrapper:hover>.btn-file-input {
//background-color: #494949;
}
#img_text {
float: right;
margin-right: -80px;
margin-top: -14px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div class="file-input-wrapper">
<button class="btn-file-input">SELECT FILES</button>
<input type="file" name="image" id="image" value="" />
</div>
<span id="img_text"></span>
</body>
Came across this question and didn't feel like any of the answers were clean. Here is my solution:
<label>
<span>Select file</span>
<input type="file" style="display: none">
</label>
When you click the label the select file dialog will open. No js needed to make it happen.
You can style the label to look like a button.
Here is an example using w3css and font awesome:
<label class="w3-button w3-blue w3-round">
<span><i class="fas fa-image"></i></span>
<input type="file" style="display: none" >
</label>
Of course you need to add an event listener to the input to detect a file was chosen.
HTML - InputFile component can be hide by writing some css.
Here I am adding an icon which overrides inputfile component.
<label class="custom-file-upload">
<InputFile OnChange="HandleFileSelected" />
<i class="fa fa-cloud-upload"></i> Upload
</label>
css-
<style>
input[type="file"] {
display: none;
}
.custom-file-upload {
border: 1px solid #ccc;
display: inline-block;
padding: 6px 12px;
cursor: pointer;
}
</style>
So I found this solution that is very easy to implement and gives a very clean GUI
put this in your HTML
<label class="att-each"><input type="file"></label>
and this in your CSS
label.att-each {
width: 68px;
height: 68px;
background: url("add-file.png") no-repeat;
text-indent: -9999px;
}
add-file.png can be any graphic you wish to show on the webpage. Clicking the graphic will launch the default file explorer.
Working Example: http://www.projectnaija.com/file-picker17.html
Just an additional hint for avoiding too much JavaScript here: if you add a label and style it like the "browse button" you want to have, you could place it over the real browse button provided by the browser or hide the button somehow differently. By clicking the label the browser behavior is to open the dialog to browse for the file (don't forget to add the "for" attribute on the label with value of the id of the file input field to make this happen). That way you can customize the button in almost any way you want.
In some cases, it might be necessary to add a second input field or text element to display the value of the file input and hide the input completely as described in other answers. Still the label would avoid to simulate the click on the text input button by JavaScript.
BTW a similar hack can be used for customizing checkboxes or radiobuttons. by adding a label for them, clicking the label causes to select the checkbox/radiobutton. The native checkbox/radiobutton then can be hidden somewere and be replaced by a custom element.
Just add negative text intent as so:
input[type=file] {
text-indent: -120px;
}
before:
after:
Oddly enough, this works for me (when I place inside a button tag).
.button {
position: relative;
input[type=file] {
color: transparent;
background-color: transparent;
position: absolute;
left: 0;
width: 100%;
height: 100%;
top: 0;
opacity: 0;
z-index: 100;
}
}
Only tested in Chrome (macOS Sierra).
the best way for it
<input type="file" id="file">
<label for="file" class="file-trigger">Click Me</label>
And you can style your "label" element
#file {
display: none;
}
.file-trigger {
/* your style */
}
As of 2022, modern browsers support file button pseudo selector. I was only struggling with Safari v16.1 which didn't work as expected and had to workaround button hiding (::-webkit-file-upload-button part).
input[type=file]::file-selector-button {
display: none;
}
input[type=file]::-webkit-file-upload-button {
display: block;
width: 0;
height: 0;
margin-left: -100%;
}
input[type=file]::-ms-browse {
display: none;
}
You may also use concise syntax:
::file-selector-button {
/* ... */
}
::-webkit-file-upload-button {
/* ... */
}
::-ms-browse {
/* ... */
}