How to change only the default cursor? - css

I have a custom cursor image for my website, but only for the default status. In the rest of cases (specially for text) I want the predefined ones.
But if I define the custom cursor this way...
html {
cursor: url('path/to/custom/cursor.svg') 0 0, default;
}
at least text status is lost (not pointer, but I suspect others have been lost as well) and my paragraphs, spans with text, headers, etc. show now my custom cursor instead of the predefined text selector one.
Of course, I could redefine styles for certain elements...
p, span, ol, ul, h1, h2, h3, h4 {
cursor: text;
}
but text status is not really linked to certain html tags, it appears when there's a text node not affected by other modifiers. For example, how can I target a div with only text, but exclude a div that contains just another div of certain color, background, etc.?
As I see in this question there's not a way to target text nodes directly, so I want to know if there's a less invasive way to define a custom cursor only in the case where the predefined default one would appear, and still showing all the predefined cursors by every modified state (text, scroll, etc.)
Thank you in advance.
Example 1: if html cursor defined, all is overridden:
html {
cursor: all-scroll;
}
Lorem ipsum dolor sit amet
Example 2: if we try to redefine some elements, we have now false positives...
html {
cursor: all-scroll;
}
/* Dillema: Which elements should be redefined to target predefined text status?? */
div {
cursor: text;
}
<div>Lorem ipsum dolor sit amet</div>
<div style="width: 100px; height: 100px; background-color: red;"></div>

TL;DR;
You can't strictly change the meaning of cursor: default; but you can style any element setting its cursor as desired.
So if you mean to address some particular elements or element types in general, you should select them pinpointing the elements with a fine grained selector (like: .classname{cursor: all-scroll;} or elementtype{cursor: all-scroll;}) but there's no selectors for element having a given property set at a given value.
If you want to get wild you may do in js:
//for every single element in the dom,
document.querySelectorAll('*')
//sets the cursor property to all-scroll if its current value is default
.foreach(el=>{ if (el.style.cursor === 'default') el.style.cursor = 'pointer'})
to set the style property of every single html element in the document that it will take the max priority.
But to just take them all via css this will be enough *{cursor: pointer;}
If you do html{cursor: all-scroll;} you won't be granted that every single elements will be styled like that because some element types don't inherit the cursor property value from its parent/ancestor and when the mouse will be over it, its style will take the precedence over the underlying html "canvas".
Anyway at a bare minimum you should set the html height at 100% in that case to make sure that that rule at least will trigger when no other element on the top layer where overriding the behaviour.
In my demo I show the 2 strategies at play and I easily demo the fact that form elements don't inherit from the parent ancestor and that when the rule is applied with *, it takes it all.
The whole story:
Here's the mdn docs about the cursor css property:
https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
The cursor CSS property sets the mouse cursor, if any, to show when
the mouse pointer is over an element.
The cursor setting should inform users of the mouse operations that
can be performed at the current location, including: text selection,
activating help or context menus, copying content, resizing tables,
and so on. You can specify either the type of cursor using a keyword,
or load a specific icon to use (with optional fallback images and
mandatory keyword as a final fallback).
It's clear that such property will affect the cursor when the mouse pointer is over the element styled like that. So to affect every elements under the root umbrella it's enough to style the whole <html> element but it's also important to make sure the visible height covers the actual viewport!
That's why it was a solution to use html { height: 100% } for example.
It should be noted that an html document has always a root element and that's <html>. Any text content is always a textNode and anywhere you find it inside the page is always the content of some node and at worst it's a child node in the body element. All I said so far it's maybe ignoring text coming from the content css property (but let's pretend it doesn't exist).
So of course you can't style the text itself but you can style the element containing it, since there's always such an element, therefor there's always a selector you can use to style a given text that for sure will be contained in some element that you can address. The only concern is that you CAN'T limit the styling to the text alone, but to the whole content of the element you are going to style.
Now the only added thing to know is that some elements will have some default values for some css properties that will override any value set on a parent element. That's because of how css specifity works and how some properties get inherited from the ancestors.
I made a demo that includes several html element types.
Plus there are two buttons:
Toggle custom cursor on html - That will toggle the css class
custom .customcursor on the html element (the rule is predefined in the document as .customcursor{cursor: all-scroll !important;})
Toggle custom cursor on * - That will add/remove a css rule that will set the cursor css property to ALL elements in the DOM (*{cursor: all-scroll !important; .. the reason why I behaved this way is to leave to css the responsability to select ALL the elements instead of using js with querySelectorAll)
It's worth pointing out that I used !important to show off that it won't be enough to override the cursor property for those element types that don't inherit from parent.
When you'll set the customcursor on html you'll see that mostly
all the elements take the customization except the form elements.
When you'll set the rule that targets ALL the elements, it will
affect EVERYTHING and that cursor will be the only one you'll see
while hovering on the whole page viewport.
//create the empty stylesheet on document loaded
var styleSheet;
document.addEventListener('DOMContentLoaded',()=>{
const styleEl = document.createElement('style');
document.head.appendChild(styleEl);
styleSheet = styleEl.sheet;
});
function toggleCustomCursorOnBody(btn){
const cb = btn.querySelector('input');
document.querySelector('html').classList.toggle('customcursor');
cb.checked = !cb.checked;
}
function toggleCssRuleOnAllElements(btn){
const cb = btn.querySelector('input');
if(!cb.checked)
addCssRule();
else
removeCssRule();
cb.checked = !cb.checked;
}
function addCssRule(){
styleSheet.insertRule('*{cursor: all-scroll !important;}', 0);
}
function removeCssRule(){
styleSheet.deleteRule(0);
}
html {
border: solid 18px purple; /*<--this is to show the size of the element we are setting cursor for! */
background: lightgoldenrodyellow;
height: calc(100% - 36px); /*<--this was what I pointed out in comments */
}
.customcursor{
cursor: all-scroll !important;
}
/*the following just to give consistence to the page elements*/
[data-label]::before{
content: attr(data-label);
padding-right: 1em;
font-weight: 600;
padding: 0 .2em;
font-size: 1rem;
background-color: #FECE44;
color: #333;
width: 100%;
max-height: 1.2rem;
}
.toggles{
margin: 0 auto 1em auto;
}
.toggle{
cursor: pointer;
padding: .5em 1em;
}
.toggle > input[type="checkbox"]{
pointer-events: none;
}
body{
font-size: 18px;
text-align: center;
}
*{
box-sizing: box-model;
border: dotted 1px lightgray;
}
.container,
form
{
display: flex;
flex-wrap: wrap;
justify-content: space-around;
gap: 2vmin;
}
body > .container{
margin-top: 2vh;
}
.container > h1,
.container > h2,
.container > h3,
.container > h4,
.container > h5,
.container > h6
{
margin: 0;
max-height: 10vh;
}
.container > h1{
background: rgba(204, 204, 204, 1);
}
.container > h2{
background: rgba(204, 204, 204, 0.9);
}
.container > h3{
background: rgba(204, 204, 204, 0.8);
}
.container > h4{
background: rgba(204, 204, 204, 0.7);
}
.container > h5{
background: rgba(204, 204, 204, 0.6);
}
.container > h6{
background: rgba(204, 204, 204, 0.5);
}
.container > p{
background-color: lime;
font-size: 2rem;
margin: 0;
}
.container > ol{
background-color: cyan;
font-size: 1rem;
padding: .5em 1em .5em 1.5em;
margin: 0;
height: fit-content;
}
.container > a{
background: antiquewhite;
font-size: 2rem;
height: fit-content;
margin: 0;
}
.container > div:not(.container):not(.unstyled) {
width: 20vw;
height: 5vh;
background: dodgerblue;
color: white;
padding: 1em;
font-weight: 600;
font-size: 1.5rem;
display: flex;
justify-content: center;
align-items: center;
}
.container > span {
width: 20vw;
height: 5vh;
background: cadetblue;
color: white;
padding: 1em;
font-weight: 600;
font-size: 1.5rem;
display: flex;
justify-content: center;
align-items: center;
}
.container > textarea{
width: 15ch;
height: 10vh;
}
.container > label{
outline: solid 1px gray;
padding: .2em 1em;
background: gray;
color: white;
max-height: 1em;
}
.container > select{
max-height: 2em;
}
.container > input{
}
.container > input[type="text"]{
width: 15ch;
max-height: 1em;
font-size: 1rem;
padding: .5rem .5rem;
}
.unstyled input[type="checkbox"]{
position: relative;
width: 2em;
height: 2em;
}
.unstyled input[type="checkbox"] + label{
}
<body>
<div class="toggles">
<button id="toggle1" class="toggle" onclick="toggleCustomCursorOnBody(this);">
Toggle custom cursor on <html>
<input type="checkbox">
</button>
<button id="toggle2" class="toggle" onclick="toggleCssRuleOnAllElements(this);">
Toggle custom cursor on *
<input type="checkbox">
</button>
</div>
[THIS IS A TEXT NODE HAVING FONT SIZE FROM BODY]
<div class="container">
<div class="container" data-label="headings">
<h1><h1></h1>
<h2><h2></h2>
<h3><h3></h3>
<h4><h4></h4>
<h5><h5></h5>
<h6><h6></h6>
</div>
<div class="container" data-label="contents">
<p><p></p>
<ol>
<li><ol> <li></li>
<li><ol> <li></li>
<li><ol> <li></li>
</ol>
<a>
</div>
<div class="container" data-label="layout">
<div><div></div>
<span><span></span>
</div>
<form class="container" data-label="form">
<label><label></label>
<input type="text" value="<input type=text>">
<textarea><textarea></textarea>
<div class="unstyled">
<input type="checkbox">
<label><input cb></label>
</div>
<select>
<option disabled selected><select>...</option>
<option value="1">Option1</option>
<option value="2">Option2</option>
<option value="3">Option3</option>
</select>
<fieldset>
<legend><legend></legend>
<div>
<input type="radio" checked>
<label><radio></label>
</div>
<div>
<input type="radio" checked>
<label><radio></label>
</div>
<div>
<input type="radio" checked>
<label><radio></label>
</div>
</fieldset>
</form>
</div>
</body>

Related

Distorted css Top for Safari

Currently I'm trying to implement some generic tooltips with no use of javascript (based only on css). For that I use a wrapper div with a wrapper css class and the tooltip class that has certain display attributes along with some margin-top and margin-left values to leave space for the hovered element.
It works on Chrome and Firefox, but in Safari the top value seems to be multiplied by the window scrolling putting way below the tooltip.
Does anyone has an idea of the workaround required for Safari?
The css classes:
.generic-tooltiptext {
visibility: hidden;
background-color: #333;
color: #fff;
border: solid thin #000;
text-align: center;
border-radius: 4px;
padding: 0px 5px;
margin-top: 20px;
margin-left: 20px;
position: absolute;
z-index: 1;
}
.generic-tooltip:hover .generic-tooltiptext {
visibility: visible;
transition-delay:0.75s;
}
This interacts with a react component:
interface GenericTooltip{
style?: CSSProperties;
text: string
}
export const GenericTooltip : React.FC<GenericTooltip> = ({style, text, children}) => {
return <div
style={style}
className="generic-tooltip">
<div className="generic-tooltiptext">
{text}
</div>
{children}
</div>
}
Just found out the problem doesn't have to do with margin: if I set margin to 0 the problem keeps appearing.
Changed the code to:
.generic-tooltiptext {
display: none;
/*--------------------*/
.generic-tooltip:hover .generic-tooltiptext {
display: block;
On the other hand, if I use display none / block as mechanism for conditional display, this "top margin" problem get's to be resolved... although the time lapse for the effect is taken out.
So there's some curious behaviour of visibility field within safari.

Display second <span> element in front of first

I'm trying to get a second sibling element displaying in front of the first - with some severe restrictions:
I cannot alter the HTML or use javascript or jQuery.
I can only use CSS.
I can't change how classes are assigned (again, I don't have access to change any code apart from the one bespoke CSS file).
The left-hand menu features a number of the above HTML structures, building a clickable menu for the sections on the page. When a page section is completed, the 'completed-section' class is added to the first span (as shown above). This is what is causing me problems:
The CSS styling of the nav-link 'button' should change when it's completed, but since I can't access the parent of a CSS-selected element I need to make these changes directly to the 'menu-number' span element, including a 'nav-link' sized background colour. So I've made the menu-number the same size as the containing 'nav-link' . But when I add a background colour to the 'menu-number' , the text in the second is obscured.
How can I 'move' the second span in front of the first so I can see its text?
I have also tried making both spans position absolute or position relative and used z-index but this pulls the spans out of the flow of the document and means the width of the menu collapses. I can't set the width to a hard-coded value because the menu toggles open and closed, width-wise, (without a class being set) and the toggled width is set by javascript which, again, I can't access.
I have also tried using display: flex on the 'a' element and reversing the 'order' of span elements. No luck.
In semi-desperation I have tried setting the direction property on 'nav-link' to rtl. No luck.
I think I've tried a couple other things too, but at this point I'll wrap this question up.
Any pointers, much appreciated...
.menu-number {
border: none;
border-left: 10px solid transparent;
border-radius: 0px;
padding-top: 13px;
padding-left: 20px;
height: 45px;
position: absolute;
width: 100%;
text-align: left;
z-index: 100;
float: left;
}
.menu-number + span {
/*position: absolute;*/
padding-left: 40px;
z-index: 200;
}
.completed-section {
color: #42bb76 !important;
border-left: 10px solid #42bb76;
background-color: #274d56;
text-decoration: underline;
}
.nav-link > div > a {
display: flex;
*/flex-direction: row-reverse;*/
}
.nav-link > div > a > span:nth-of-type(1) {
order: 2;
}
.nav-link > div > a > span:nth-of-type(2) {
order: 1;
}
.nav-link > div > a > .section-name {
color: white;
padding: 13px 20px 0px 60px;
height: 45px;
float: left;
}
<div class="nav-link">
<div>
<a href="scroll/to/section">
<span class="menu-number completed-section">1.</span>
<span class="section-name">Section name</span>
</a>
</div>
</div>
I've also tried 'flex-direction' but I've now commented that out.
You can achieve this using CSS order property:
Here is the fiddle:
.menu-number {
order: 2;
}
.section-name {
order: 1;
}
.nav-link a{
display: flex;
}
<div class="nav-link">
<div>
<a href="scroll/to/section">
<span class="menu-number completed-section">1.</span>
<span class="section-name">Section name</span>
</a>
</div>
</div>

Button and link styles behaving differently

I have two elements (<a> and <button>), both of which are sharing the same classes from Tachyons:
<a class="f4 br2 fw9 pa3 bg-dark-blue white link db tc lh-solid fixed left-1 bottom-1 right-1 mla mra z-1 " href="/edit-profile/photos"
>Confirm account</a>
<button class="f4 br2 fw9 pa3 bg-dark-blue white link db tc lh-solid fixed left-1 bottom-1 right-1 mla mra z-1 " type="submit">Next</button>
The expected behaviour is that they will both be the same width, and yet they're different (despite the same styles).
Any idea what's going on here?
Here's a Codepen demonstrating the issue.
In your particular case the button has a border and a different font, which is a default style for your browser. Each browser have it's own defaults for every type of elements, that's why a button and a link would look the way they do without any styling. In a matter of fact it isn't right to say "without any styling", it is rather "without any additional styling":
<button>I'm a button</button>
I'm a link
I didn't go through all the css you have, because you have 17 classes for a single element and I'm too lazy for it, but it actually possible to have different styles for different elements with a common class:
.awesome {
display: inline-block;
border: 5px solid;
width: 200px;
box-sizing: border-box;
padding: 20px;
text-align: center;
margin: 10px 0 10px 10px;
font-family: Arial, serif;
}
div.awesome {
background-color: deepskyblue;
border-color: royalblue;
font-style: italic;
color: darkslateblue;
}
span.awesome {
background-color: orangered;
border-color: firebrick;
font-weight: bold;
color: gold;
}
<div class="awesome">I'm a div</div>
<span class="awesome">I'm a span</span>

Hiding pseudo css element when data attribute is empty

I have the following badge that I can add to any element:
.notification-badge {
position: relative;
}
.notification-badge:after {
content:attr(data-badge);
position:absolute;
top:-10px;
right:-10px;
min-width: 10px;
padding: 3px 7px;
font-size: 12px;
font-weight: 700;
line-height: 1;
background-color: $brand-danger;
color: #fff;
text-align: center;
white-space: nowrap;
vertical-align: middle;
border-radius: 10px;
border: 2px solid #fff;
}
It's fairly straightforward, the element that I attach the badge class onto provides a data-badge attribute with some number, which gets shoved into the :after element's content.
I would like the badge to not appear at all if content is empty. I've tried using the :empty selector, but it doesn't work because the actual tag may still contain other elements, for instance:
<a href="/cart" class="notification-badge" data-badge="">
<i class="fa fa-shopping-cart"></i>
</a>
In this case, I'd want the shopping cart icon and link to still exist, but have the notification-badge class not render the badge.
So, I suppose I could give up on the idea of it being a pure pseudo element and just make it a span with the number inside of it instead of a data- attribute, but it seems like there is probably an easy way to do this that I'm just not aware of.
This works for me:
.notification-badge:after {
visibility: hidden;
}
.notification-badge[data-badge]:after {
visibility: visible;
}
The :empty selector selector matches every element that has no children (including text nodes) W3Schools
So what you could do is here do something like this:
.notification-bade .fa-shopping-cart {visibility:visible}
.notification-badge:after {
content:attr(data-badge); visibility: hidden
}

Strange behaviour when using text-align justify/text-justify and right

I ran into one IE-specific problem that I just can't wrap my head around.
The following HTML and CSS can be seen live in this pen.
:: HTML
<div id="container">
<div class="dummy">Dummy</div>
<nav>
<div id="right">
<ul>
<li>Lorem ipsum <img src="http://placehold.it/80x40"> dolor sit amet.</li>
<li>Anal natrach, ut vas petat, <img src="http://placehold.it/80x40"> doriel dienve.</li>
</ul>
<div class="dummy">Dummy</div>
<div class="dummy">Dummy</div>
</div>
</nav>
</div>
:: CSS
/* RESET */
* { margin: 0; padding: 0; vertical-align: top; }
ul { list-style: none; }
/* MARKUP */
#container {
line-height: 0;
font-size: 0rem;
text-align: justify;
text-justify: distribute-all-lines;
}
#container:after {
content: '';
display: inline-block;
width: 100%;
}
#container > * {
display: inline-block;
line-height: 1;
font-size: 1rem;
text-align: left;
text-justify: none; /* does not work */
}
#container nav {
text-align: right;
}
#right > * {
display: inline-block;
}
/* COLORS & STUFF */
#container { padding: 10px; background: #cfc; }
.dummy { padding: 10px; background: #ffc; }
#container nav { padding: 10px; background: #ccf; }
ul { padding: 10px; background: #fcc; }
So, what's the Problem?
The content of the green div is justified, while each child of the very div in turn is given text-align: left;. Those children are: the left dummy div and the bluish nav.
The nav contains a list (red), and two dummies. For the red list's items the text-align is set to right - and there's lies the problem (or at least, there you can see it).
The first image is shifted to the left (and thus overlays/hides some piece of the text). The second image (and thus the whole second list item) is fine. This, however, changes, when changing the text. It seems as if only the image of the longest (meaning widest) item stays where it should be - all other images (if you were to create some more items) are shifted - depending on the list item's width, that is.
Now, why is that so - and how can I fix it?
The following things I found out so far:
When setting the li { text-align: left; } the image stays fine in between the two text portions - but I don't get right alignment, of course.
When removing text-justify from the #container the image stays fine as well.
Setting text-justify either to auto or to none does not seem to work...
Once again: this is just regarding Internet Explorer (9+).
// EDIT
In order to avoid your time being spent on something I'm not interested in, I'll post something more on what I'd like to have.
The final code must
keep the current/desired functionality (i.e., justified alignment);
work in all major browsers (current version and at least one before that).
The final code must not
contain floats;
contain absolute/relative positions.
// EDIT
Here is a screenshot of the desired result (Firefox), and one of what I get in IE...
Change your text-justify to distribute (Tested in IE10, IE9, Chrome, FF):
text-justify: distribute;
Check out the codepen to see it in action.
Did you try by setting like this?
li img{display: inline-block; margin: 0 5px;} /*you could set margin: 1px; only*/
your code pen

Resources