Can focus-within exclude certain elements? - html

I've got a stepper component like this
Note the DOM is something like
<div class="my-stepper">
<button>-</button>
<input type='number' />
<button>+</button>
</div>
I was using .my-stepper:focus-within to ensure that the whole stepper looks focused when you're in the the input
But I don't like that when you focus a button, you end up with a doubled up focus
I was hoping to use something like .my-stepper:focus-within:not(button:focus) to ensure that if the focus is on the input, container should look focused, but if focus is on a button, the container should NOT look focused.
How can I get the effect I'm looking for without changing my DOM?

:has() should give you what you want. Though keep in mind the browser support isn't 100% currently. But I think this falls nicely under progressive enhancement.
MDN
.my-stepper:focus-within {
outline: 1;
}
.my-stepper:has(button:focus) {
outline: 0;
}

consider extracting your buttons outside of container. This will let you focus within stepper only:
.box {
position: relative;
width: 100px;
}
.btn-layer {
top:0;
position: absolute;
}
.minus {
left: 0;
}
.plus {
right: 0
}
input {
width: 20px;
}
<div class="box">
<div class="my-stepper">
<input type='number' />
</div>
<div class="btn-layer">
<button class="minus">-</button>
<button class="plus">+</button>
</div>
</div>

Related

Keyboard access is not working for inside div with buttons when user hovers the div we are displaying buttons. How to implement accessibility?

I have div container with two buttons. When user mouse hover or keyboard focus I am showing that button. I am not able to access those button through keyboard.
Below is my sample HTML and CSS code.
<div class="ui-col ui-dropzone" tabindex="0">
<div class="ui-edit-bar">
<div class="label"></div>
<button tabindex="0" data-action="edit">Edit Row</button>
<button tabindex="0" data-action="edit">Edit Col</button>
</div>
</div>
.ui-col:hover, .ui-col:focus {
border: 1px dashed #17a2b8;
}
.ui-edit-bar {
display: none;
position: absolute;
height: 30px;
width: max-content;
padding: 0 8px;
color: #FFF;
font-family: sans-serif;
font-size: 11px;
white-space: nowrap;
z-index: 10000;
}
.ui-col:hover > .ui-edit-bar,
.ui-col:focus > .ui-edit-bar {
display: block;
}
Able to access div using keyboard. But I am not able to access buttons through keyboard.
Your CSS is causing the problem.
You only display the edit bar when the <div class="ui-col ui-dropzone" tabindex="0"> is focused.
When you focus an item within that div it no longer has focus, so it reverts to display: none; and that then hides the <button>s from the accessibility tree.
You could use the :focus-within pseudo selector and make the parent opacity 0 but the support is not great for :focus-within yet.
.ui-col.ui-dropzone{
opacity: 0;
}
.ui-col.ui-dropzone:hover,
.ui-col.ui-dropzone:focus-within{
opacity: 1;
}
<div class="ui-col ui-dropzone">
<div class="ui-edit-bar">
<div class="label"></div>
<button data-action="edit">Edit Row</button>
<button data-action="edit">Edit Col</button>
</div>
</div>
Realistically though (due to poor support for :focus-within) you would likely need a JavaScript fallback that changes the parent class when a button is focused and use that to control the opacity.
The advantage of this approach is that you are not having to add tabindex="0" everywhere so you code will be easier to maintain.

Clicking on label not working in HTML

I'm trying to make a custom file selection button in HTML and CSS.
I've read on the internet that it can be done, hiding the original button and 'drawing' a new one over it, like so:
HTML:
<div class="upload">
<input type="file" class="upload" name="upload"/>
</div>
CSS:
div.upload {
width: 157px;
height: 57px;
background-color: silver;
}
div.upload input {
display: block !important;
width: 157px !important;
height: 57px !important;
opacity: 0 !important;
overflow: hidden !important;
}
And it's working, obviously... but I want only a text, not a image.
So I tried it like this way:
<div class="upload">
Choose File
<input type="file" class="upload" name="upload"/>
</div>
And it won't work when I click on the label. It only works when I click below it.
Why doesn't this work and how can I make this work? I also tried with pointer-events and nothing...
You have to assign your text to your <button>, using a <label> with a for attribute equal to the id of the <input>.
<div class="upload">
<label class="uploadLabel" for="uploadBtn"> Choose File</label>
<input id="uploadBtn" type="file" class="upload" name="upload" />
</div>
In order to completely cover the button with your label, you'll also have to add absolute positioning.
.uploadLabel {
position: absolute;
}
Demo
Why is this necessary?
The event is triggered on your button. This basically means, clicking on a plain text element won't do anything. To trigger a click event on your button, you simply delegate the click on your label to your button.
use an actual label element. that will take care of delegating the click from the container to the input.
set opacity to 0, as you did in your original post (another, more verbose, and arguably more semantic approach will be to position the input absolutely and the label relatively, and set a lower z-index to the input. that will cover the input completely, effectively hiding it — see the second example).
the benefit here is you get clickable area that matches the label surface only, so you can style and set the dimensions to the label alone.
.upload {
display: block;
width: 157px;
height: 57px;
background-color: blue;
}
.upload input {
opacity: 0;
}
<label class="upload">
Choose File
<input type="file" class="upload" name="upload" />
</label>
… and the more verbose approach:
.upload {
position: relative;
display: block;
width: 157px;
height: 57px;
background-color: blue;
}
.upload input {
position: absolute;
z-index: -1;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
<label class="upload">
Choose File
<input type="file" class="upload" name="upload" />
</label>

Button to make other div visible

I am fairly new and just experiencing with some html/css . I was planning to make a login screen pop up in the middle of when a user clicks "login".
i've set up a div which is hidden on the screen and i want to make it visible when the user clicks on "login"
the problem i'm having is making the Div visible again . Here is the CSS:
#loginscreen {
position: absolute;
width: 400px;
height: 500px;
top:0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
border: 2px solid black;
border-radius: 40px;
background-color: lightgrey;
visibility: hidden;
z-index: 1000;
}
.loginbtn:active + #loginscreen
{
visibility: visible
}
:active only works for as long as the element is being clicked. As soon as the click is no longer being held the element will no longer be active.
Try using Javascript to do this, for example:
<button type="button" onclick="document.getElementById('<id-of-div>').style.visibility = 'visible'"> Login </button>
Where <id-of-div> is whatever id you have assigned to the div you wish to make visible.
You cannot trap a user event ("click") without using javascript (or, better yet, jQuery). As a beginner, I first suggest you use jQuery rather than pure javascript. For one thing, it's much less typing and (imho) far easier to master. You code in jQuery, and behind the scenes jQuery turns that into javascript at runtime. To use jQuery, all you must do is include the jQuery library in the <head> tags of each page, like this:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
</head>
The jQuery to show the login form would look something like this:
$('#mybutt').click(function(){
$('#loginscreen').fadeIn(800);
});
Here is an example you can use for ideas:
jsFiddle Demo
$('#mybutt').click(function(){
$('#loginscreen').fadeIn(800);
});
$('#logX').click(function(){
$('#loginscreen').fadeOut(800);
});
div{position:relative;box-sizing:border-box;}
#loginscreen {
position: absolute;
width: 400px;
height: auto;
top:0;
right: 0;
border: 1px solid #ddd;
border-radius: 4px;
background-color: lightgrey;
z-index: 1000;
display:none;
}
#logHead{width:100%;height:40px;padding:5px;background:darkcyan;color:white;overflow:hidden;}
#headLeft{float:left;width:80%;}
#headRight{float:right;width:20px;padding:5px;border:1px solid green;cursor:pointer;}
#logTop{width:100%;padding:20px;}
#logUN{width:100%;}
#logPW{width:100%;}
#logBott{width:100%;padding-left:80%;overflow:hidden;}
#loginscreen input{font-size:1.5rem;border:1px solid #ddd;}
button{font-size:1.5rem;color:white;background:darkcyan;cursor:pointer;}
#mybutt{position:absolute;bottom:150px;left:50px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="loginscreen">
<div id="logHead">
<div id="headLeft">Login:</div>
<div id="headRight"><div id="logX">X</div></div>
</div>
<div id="logTop">
<div id="logUN"><input type="text" id="username" placeholder="user"/></div>
<div id="logPW"><input type="text" id="password" placeholder="pass"/></div>
</div>
<div id="logBott">
<button>Login</button>
</div>
</div>
<input type="button" id="mybutt" value="Login" />
Since you are new to jQuery, here are some free beginner-level tutorials to get you started. (It's where I learned myself, and they're free)

How to make div/container change background color when child element has focus?

I have the following html:
<div class="mydiv">
<p>some text here</p>
<input type='text' />
</div>
...with the following CSS:
.mydiv {
background-color:yellow;
}
.mydiv:focus, .mydiv:hover {
background-color:orange;
}
The :hover is changing the background color appropriately, but the :focus is not having any effect. Is this because the <div> cannot truly have focus?
Is there a CSS solution to make .mydiv change background color when any of its children receive focus?
Here's a fiddle.
There is no CSS solution for this. But, you can achieve this by using jQuery.
$(".mydiv").children().focus(function() {
$(this).parent().css("background-color", "orange");
}).blur(function() {
$(this).parent().css("background-color","yellow");
});
Here is the Fiddle
You have to add the tabindex attribute to the element needs to be focusable.
Here is the Fiddle
But, to answer your question, there is no pure CSS solution to make the div bg color change if its children receive focus.
When using jQuery, I think you're better off using the focusin and focusout events.
The code as adapted from the accepted answer would then become:
$(".mydiv").focusin(function() {
$(this).css("background-color", "orange");
}).focusout(function() {
$(this).css("background-color","yellow");
});
though, personally, I'd rather use a "focus" class:
$(".mydiv").focusin(function() {
$(this).addClass("focus");
}).focusout(function() {
$(this).removeClass("focus");
});
combined with the css for the combined selector:
.mydiv.focus { background-color: orange }
p.s. For once, I find the bit of docs on w3schools more informative than the demo on api.jquery.com, which just looks confusing to me.
Possible CSS solution:
<style>
#row1 {display: block; position: relative; width: 100%; background-color: #ffffff; z-index: 150;}
.BGmagic {display: none; position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; background-color: #efefef; z-index: 200;}
#inputone{display: block; position: relative; z-index: 250;}
#inputone:focus + .BGmagic {display: block;}
#inputone:hover + .BGmagic {display: block;}
</style>
<form>
<div ID="row1">
<p style="position: relative; z-index: 250;">First name:</p>
<input ID="inputone" type="text" name="firstname">
<div class="BGmagic"></div>
</div>
</form>

How to merge HTML input box and a button? (sample images attached)

Please answer the following questions:
How to merge search box and search button as shown in below example1 and example2? The box and button are joined together.
How to put 'magnifier' icon on the left side of the search box?
How to put a default text into the box like 'Search for items' and fade it when user clicks on the box.
Example1
Example2
Example3 (I don't want a separate button as shown below)
Please help! Thanks!!
Easiest way is to make the entire text field wrapper, from the icon on the left to the button on the right, one div, one image.
Then put a textfield inside that wrapper with a margin-left of like 30px;
Then put a div inside the wrapper positioned to the right and add a click listener to it.
HTML:
<div id="search_wrapper">
<input type="text" id="search_field" name="search" value="Search items..." />
<div id="search_button"></div>
</div>
CSS:
#search_wrapper{
background-image:url('/path/to/your/sprite.gif');
width:400px;
height:40px;
position:relative;
}
#search_field {
margin-left:40px;
background-transparent;
height:40px;
width:250px;
}
#search_button {
position:absolute;
top:0;
right:0;
width:80px;
height:40px;
}
JQuery:
$(function(){
// Click to submit search form
$('#search_button').click(function(){
//submit form here
});
// Fade out default text
$('#search_field').focus(function(){
if($(this).val() == 'Search items...')
{
$(this).animate({
opacity:0
},200,function(){
$(this).val('').css('opacity',1);
});
}
});
});
For your first question, there are many ways to accomplish the joining of the button to the search box.
The easiest is to simply float both elements to the left:
HTML:
<div class="wrapper">
<input placeholder="Search items..."/>
<button>Search</button>
</div>
CSS:
input,
button {
float: left;
}
Fiddle
This method has some limitations, however, such as if you want the search box to have a percentage-based width.
In those cases, we can overlay the button onto the search box using absolute positioning.
.wrapper {
position: relative;
width: 75%;
}
input {
float: left;
box-sizing: border-box;
padding-right: 80px;
width: 100%;
}
button {
position: absolute;
top: 0;
right: 0;
width: 80px;
}
Fiddle
The limitation here is that the button has to be a specific width.
Probably the best solution is to use the new flexbox model. But you may have some browser support issues.
.wrapper {
display: flex;
width: 75%;
}
input {
flex-grow: 2;
}
Fiddle
For your second question (adding the magnifier icon), I would just add it as a background image on the search box.
input {
padding-left: 30px;
background: url(magnifier.png) 5px 50% no-repeat;
}
You could also play around with icon fonts and ::before pseudo-content, but you'll likely have to deal with browser inconsistencies.
For your third question (adding placeholder text), just use the placeholder attribute. If you need to support older browsers, you'll need to use a JavaScript polyfill for it.
It's all in the CSS... You want something like this:
http://www.red-team-design.com/how-to-create-a-cool-and-usable-css3-search-box
Also, for the search icon:
http://zenverse.net/create-a-fancy-search-box-using-css/
Src: Quick Google.
You don't merge them, rather you give the illusion that you have. This is just CSS. Kill the search box borders, throw it all into a span with a white background and then put the fancy little dot barrier between the two things. Then toss in some border radius and you are in business.
The above tut might look too lengthy. The basic idea is this:
Arrange the input box just like you do. The input text box should be followed by the button. add the following css to do that.
position:relative;
top:-{height of your text box}px;
or you can use absolute positioning.
<div id="search_wrapper">
<input type="text" id="search_field" name="search" placeholder="Search items..." />
<div id="search_button">search</div>
</div>
#search_wrapper{
background-color:white;
position:relative;
border: 1px solid black;
width:400px;
}
#search_field {
background-transparent;
border-style: none;
width: 350px;
}
#search_button {
position:absolute;
display: inline;
border: 1px solid black;
text-align: center;
top:0;
right:0;
width:50px;
}
http://jsfiddle.net/zxcrmyyt/
This is pretty much easy if You use bootstrap with custom css
My output is diffrent but the logic works as it is..
I have used Bootstrap 5 here you can also achieve this by using Pure CSS,
<div class="container my-5">
<div class="row justify-content-center">
<div class="col-10 p-0 inputField text-center">
<input type="text" id="cityName"placeholder="Enter your City name..">
<input type="submit" value="search" id="submitBtn">
</div>
</div>
</div>
For Styling
#import url('https://fonts.googleapis.com/css2?family=Ubuntu&display=swap');
* {
font-family: 'Ubuntu', sans-serif;
}
.inputField {
position: relative;
width: 80%;
}
#cityName {
width: 100%;
background: #212529;
padding: 15px 20px;
color: white;
border-radius: 25px;
outline: none;
border: none;
}
#submitBtn {
position: absolute;
right: 6px;
top: 5px;
padding: 10px 20px;
background: rgb(0, 162, 255);
color: white;
border-radius: 40px;
border: none;
}
Hear is an Example !
https://i.stack.imgur.com/ieBEF.jpg