Is there a CSS ":drop-hover" pseudo-class? - html

Saying I have an input type="file" field. One can drop a file on this input(like in Firefox) instead of clicking "browse" and selecting the file.
Now, I want to customize it a bit, by changing the field's background color when one is about to drop a file in the input. I cannot really use :hover since it matches even when you're not drag&dropping. Is there a CSS (pseudo-class) to do that?
And is there a CSS way to style different if the file being dropped is not accepted and if it is? Say, if the field accepts only PNG files using accept attributes, I would make the field green if you're about to drop a PNG file on it, and red if that's another type of file.
Is there a CSS way to do these today? Is there a planned way to do so in CSS (like in upcoming specs/in current specs but not implements anywhere)?

UPDATE: Thanks to #Renato's comment, according to https://github.com/w3c/csswg-drafts/issues/2257, the drop pseudo-class has been dropped now.
There is :drop and :drop() pseudo-class, which is currently in Working Draft status.
According to [moderator: link to spam removed], the browser support is not good.
For "file being dropped is not accepted" case, :drop(invalid active) is expected to work, in future.

I had the same question and solved it a little differently than nashcheez. Still using JavaScript, though (I used jQuery here to simplify things):
function drag(ev) {
ev.dataTransfer.setData("text", "foo");
}
function allowDrop(ev) {
$(ev.target).attr("drop-active", true);
ev.preventDefault();
}
function leaveDropZone(ev) {
$(ev.target).removeAttr("drop-active");
}
function drop(ev) {
ev.preventDefault();
$(ev.target).removeAttr("drop-active");
alert(ev.dataTransfer.getData("text"));
}
#draggableItem {
height: 50px;
width: 150px;
background-color: #eee;
}
#dropZone {
height: 50px;
width: 150px;
background-color: #efe;
}
#dropZone[drop-active=true] {
box-shadow: inset 0px 0px 0px 2px #00C;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="draggableItem" draggable="true" ondragstart="drag(event);">Drag Me</div>
<div id="dropZone" ondragover="allowDrop(event);" ondragleave="leaveDropZone(event);" ondrop="drop(event);">Drop Here</div>
I've tested this on Safari, Firefox and Chrome, but I haven't tried IE. I'm probably breaking a rule with the custom attribute, but it seems to work while I'm waiting for CSS4.

There is absolutely no pure css cross-browser solution currently for changing element's properties when dragging and dropping elements into the browser window.
What you are trying to do here can be achieved by Javascript/jQuery using a hidden container and showing it only when the object is inside the draggable container.
There is this demo I had saved earlier if you would like to have a look into:
var resetTimer;
var reset = function() {
$('#d1').hide();
};
var f = function(e) {
var srcElement = e.srcElement ? e.srcElement : e.target;
if ($.inArray('Files', e.dataTransfer.types) > -1) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = (srcElement.id == 'd1') ? 'copy' : 'none';
if (e.type == "dragover") {
if (resetTimer) {
clearTimeout(resetTimer);
}
$('#d1').show();
console.info('dropped on <' + srcElement.tagName.toLowerCase() + ' id="' + srcElement.id + '">\n\ne.dataTransfer.types is ' + e.dataTransfer.types + '\n\ne.dataTransfer.files.length is ' + (e.dataTransfer.files ? e.dataTransfer.files.length : 0));
} else if (e.type == "dragleave") {
resetTimer = window.setTimeout(reset, 25);
} else if (e.type == "drop") {
reset();
alert('dropped on <' + srcElement.tagName.toLowerCase() + ' id="' + srcElement.id + '">\n\ne.dataTransfer.files.length is ' + (e.dataTransfer.files ? e.dataTransfer.files.length : 0));
}
}
};
document.body.addEventListener("dragleave", f, false);
document.body.addEventListener("dragover", f, false);
document.body.addEventListener("drop", f, false);
body {
border: 1px solid black;
}
#d0,
#d2 {
border: 1px solid black;
}
#d1 {
border: 1px solid black;
display: none;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="d0">drag files onto this page</div>
<div id="d1">-> drop here <-</div>
<div id="d2">and stuff will happen</div>
</body>

There is no CSS-Solution. My isue was to change Color on drag-over (Chrome does not support, Opera does)
I do it this way:
`<input id="xyz" type="FILE" value=""
ondragover ="this.style.backgroundColor='#88FF88';"
ondragleave="this.style.backgroundColor='#FFFFFF';"
/>
<input type="button" onclick="srFU(this);" value="send File" />`

Related

jQuery Setting Element Styles Based On Modal Visibility Behaves Differently in Firefox and Chrome

I'm new to jquery and javascript. I have a website with multiple unique modal/popups that are triggered via a CSS :target selector, which sets them to display: block. I'm trying to use jquery to hide a separate element among other things.
The logic is:
If a modal is visible, then hide element. Else show element. I'm currently using popstate in my jquery. This is because the modals can close if the user presses their browser back button. So I don't want to use any click functions. Everything seems to be working fine, except the if/else statements that detect the visibility of the modals seem to behave differently between Firefox and Chrome? When it hides the element in Firefox, it shows it Chrome. When it hides it in Chrome, it shows it in Firefox. Why the opposite behavior? What am I doing wrong?
$(window).on('popstate', function(event) {
if ($('.modal').is(':visible')) {
console.log("Modal ON");
$('#wrapper').css('overflow-y', 'hidden');
$('#extra_element').css('display', 'none');
} else {
console.log("Modal OFF");
$('#wrapper').css('overflow-y', 'scroll');
$('#extra_element').css('display', 'block');
}
});
.modal {
display: none;
width: 100px;
height: 100px;
background-color: red;
margin: 0 auto;
}
.modal:target {
display: block;
}
#extra_element {
width: 100vw;
height: 20vh;
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="extra_element">This element should hide when modal is open</div>
<div>
Click Me To Open Modal
<div id="content" class="modal">I'm a Modal. Press browser back button to close
</div>
</div>
Alternate jQuery:
Setting the length to 1 works in Firefox and works oppositely in Chrome.
Setting the length to 0 works in Chrome and works oppositely in Firefox.
$(window).on('popstate', function(event) {
if ( $('.modal-overlay:visible').length === 1 ) {
console.log("Modal ON");
$('#wrapper').css('overflow-y', 'hidden');
$('#extra_element').css('display', 'none');
}
else {
console.log("Modal OFF");
$('#wrapper').css('overflow-y', 'scroll');
$('#extra_element').css('display', 'block');
}
});
Is there another way to do this correctly?
This would be a Chrome bug, according to the specs, at the step 10 of the History traversal algorithm the UA should call the "scroll to fragment" algorithm which is responsible for updating the document's target element (:target) and only at the step 18.1 it should fire the popstate event.
Chrome does fire the event before it updates the document's target element, and thus your CSS :target selector doesn't match yet.
I did open an issue so they get this in-line with the standards, but for the time being you can workaround that by waiting just a task after the event fired:
$(window).on('popstate', async function(event) {
await new Promise(res => setTimeout(() => res()));
if ($('.modal').is(':visible')) {
console.log("Modal ON");
$('#wrapper').css('overflow-y', 'hidden');
$('#extra_element').css('display', 'none');
} else {
console.log("Modal OFF");
$('#wrapper').css('overflow-y', 'scroll');
$('#extra_element').css('display', 'block');
}
});
.modal {
display: none;
width: 100px;
height: 100px;
background-color: red;
margin: 0 auto;
}
.modal:target {
display: block;
}
#extra_element {
width: 100vw;
height: 20vh;
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="extra_element">This element should hide when modal is open</div>
<div>
Click Me To Open Modal
<div id="content" class="modal">Press browser back button to close
</div>
</div>

What is the meaning of adding ondragstart="return false;" to an <img> tag?

I found some web pages have added
ondragstart="return false;" to an <img> tag like this:
<img ondragstart="return false;" src="...." .....
May I know what's the benefit from it?
It just makes the image undraggable, preventing this:
Which could also be achieved using a background-image with css instead <img> tag.
ondragstart is used in conjunction with draggable="true" to trigger a function on a draggable element:
<div draggable="true" ondragstart="function()">
This can be seen here:
var dragged;
/* events fired on the draggable target */
document.addEventListener("drag", function(event) {
}, false);
document.addEventListener("dragstart", function(event) {
// store a ref. on the dragged elem
dragged = event.target;
// make it half transparent
event.target.style.opacity = .5;
}, false);
document.addEventListener("dragend", function(event) {
// reset the transparency
event.target.style.opacity = "";
}, false);
/* events fired on the drop targets */
document.addEventListener("dragover", function(event) {
// prevent default to allow drop
event.preventDefault();
}, false);
document.addEventListener("dragenter", function(event) {
// highlight potential drop target when the draggable element enters it
if (event.target.className == "dropzone") {
event.target.style.background = "purple";
}
}, false);
document.addEventListener("dragleave", function(event) {
// reset background of potential drop target when the draggable element leaves it
if (event.target.className == "dropzone") {
event.target.style.background = "";
}
}, false);
document.addEventListener("drop", function(event) {
// prevent default action (open as link for some elements)
event.preventDefault();
// move dragged elem to the selected drop target
if (event.target.className == "dropzone") {
event.target.style.background = "";
dragged.parentNode.removeChild(dragged);
event.target.appendChild(dragged);
}
}, false);
#draggable {
width: 200px;
height: 20px;
text-align: center;
background: white;
}
.dropzone {
width: 200px;
height: 20px;
background: blueviolet;
margin-bottom: 10px;
padding: 10px;
}
<div class="dropzone">
<div id="draggable" draggable="true" ondragstart="event.dataTransfer.setData('text/plain',null)">
This div is draggable
</div>
</div>
<div class="dropzone"></div>
<div class="dropzone"></div>
<div class="dropzone"></div>
The return false in the example is shorthand for stating that the function does nothing, and is essentially completely extraneous.
Also note that while ondragstart can be processed by mobile devices, the dragstart event is not compatible with mobile, so to ensure dragging for mobile devices you will want to use touchstart instead.

How do I finish this html code for custom browser New Tab?

Someone I know was browsing the web and every time they opened a new tab it opened a completely blank homepage with the ability to type freely onto the newly opened page. Whatever they ended up typing they would press Enter and it would search just as if they had typed it in the Browsers address bar.
I asked them how they did that and they provided me with this code:
 html { overflow:hidden; } I tried to emulate what they did by saving that as an html file and opening it with my browser but it would just open to a completely blank page and I didn't have the ability to type anything. So I think that when they gave me the code it was cutoff because of a character limit in the chat that we were using. Would anyone know how to finish this to be able to do what I described they did. I would like to replicate it for myself every time I open a new tab.
Thank you to anyone that can help!
You just need a text input the size of the entire page, and when you press enter, the window location should just be the content of the text input.
For a URL search
var text = document.getElementById("text");
document.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
window.location = "https://" + text.value;
}
});
html
{
padding:0;
margin: 0;
overflow:hidden;
}
textarea
{
outline: none;
border:none;
resize: none;
width: 100vw;
height: 100vh;
}
<html>
<textarea autofocus id="text"></textarea>
</html>
For a Google search
document.getElementById("search").addEventListener( "keypress", function( event ){
if( event.keyCode === 13 )
{
event.preventDefault();
window.location = "https://google.com/search?q=" + encodeURI( this.value );
}
})
html,body {
padding: 0;
margin: 0;
overflow:hidden;
}
#search {
width: 100vw;
height: 100vh;
border: none;
outline: none;
font-size: 30px;
text-align: center;
}
<html>
<head>
<title></title>
</head>
<body>
<input id = "search" autofocus>
</body>
</html>

Changing background color on input focus with css alone

Am trying to change the background color of an input holder once the input is clicked i used these
<div class="name"> <input type="text" class="input-name"></div>
CSS
.input-name:focus + .name{
background:#f00;
}
this is how it is normally
this is what i want on focus
but it wont Work
You cannot select a parent element with CSS.
However. you can fake something similar with a box shadow
body {
margin: 25px; /* not required */
}
.input-name:focus {
box-shadow:0 0 0 10px red;
}
<div class="name">
<input type="text" class="input-name" />
</div>
While the exact thing you want can't be done, #Paulie_D 's answer was the closest with pure css.
To do exactly what you wanted you would need to use javascript because, as aforementioned, you can't select a parent element.
Here's the javascript:
function myFunction() {
document.getElementById("name").style.background = "red";
}
And the HTML:
<div id="name>
<input type="text" id="input" onfocus="myFunction()">
Unfortunately, you can't select a parent with CSS.
Is there a CSS parent selector?
This will have to be done via script.
(function() {
var inputs = document.getElementsByClassName('input-name');
if( !(inputs && inputs.length) ) return;
function toggleRed(elem) {
elem.classList.toggle('red');
}
for(var i=0; i < inputs.length; i++) {
var input = inputs[i];
// focus
input.addEventListener('focus', function() {
toggleRed(this.parentElement);
});
// blur
input.addEventListener('blur', function() {
toggleRed(this.parentElement);
});
}
})();
Check this for a demo
http://jsfiddle.net/andyw_/6ec1efs2/1/
You can use pseudo-class :has(child)
so:
.name:has(.input-name:focus-visible) {
background:#f00;
}

HTML5 placeholder disappears on focus

Is there a freely available jQuery plugin that changes placeholder behavior to match HTML5 spec?
Before Focus
On Focus Good (Safari)
On Focus Bad (Chrome, Firefox)
You can what your browser does with this simple fiddle.
HTML5 draft spec says:
User agents should present this hint to the user, after having stripped line breaks from it, when the element's value is the empty string and/or the control is not focused (e.g. by displaying it inside a blank unfocused control and hiding it otherwise).
The "/or" is new in current draft so I suppose that's why Chrome and Firefox don't support it yet. See WebKit bug #73629, Chromium bug #103025.
Stefano J. Attardi wrote a nice jQuery plugin that just does that.
It is more stable than Robert's and also fades to a lighter grey when the field gets focused.
See the demo page
Grab it on GitHub
Play with the fiddle
I modified his plugin to read placeholder attribute as opposed to manually creating a span.
This fiddle has complete code:
HTML
<input type="text" placeholder="Hello, world!">
JS
// Original code by Stefano J. Attardi, MIT license
(function($) {
function toggleLabel() {
var input = $(this);
if (!input.parent().hasClass('placeholder')) {
var label = $('<label>').addClass('placeholder');
input.wrap(label);
var span = $('<span>');
span.text(input.attr('placeholder'))
input.removeAttr('placeholder');
span.insertBefore(input);
}
setTimeout(function() {
var def = input.attr('title');
if (!input.val() || (input.val() == def)) {
input.prev('span').css('visibility', '');
if (def) {
var dummy = $('<label></label>').text(def).css('visibility','hidden').appendTo('body');
input.prev('span').css('margin-left', dummy.width() + 3 + 'px');
dummy.remove();
}
} else {
input.prev('span').css('visibility', 'hidden');
}
}, 0);
};
function resetField() {
var def = $(this).attr('title');
if (!$(this).val() || ($(this).val() == def)) {
$(this).val(def);
$(this).prev('span').css('visibility', '');
}
};
var fields = $('input, textarea');
fields.live('mouseup', toggleLabel); // needed for IE reset icon [X]
fields.live('keydown', toggleLabel);
fields.live('paste', toggleLabel);
fields.live('focusin', function() {
$(this).prev('span').css('color', '#ccc');
});
fields.live('focusout', function() {
$(this).prev('span').css('color', '#999');
});
$(function() {
$('input[placeholder], textarea[placeholder]').each(
function() { toggleLabel.call(this); }
);
});
})(jQuery);
CSS
.placeholder {
background: white;
float: left;
clear: both;
}
.placeholder span {
position: absolute;
padding: 5px;
margin-left: 3px;
color: #999;
}
.placeholder input, .placeholder textarea {
position: relative;
margin: 0;
border-width: 1px;
padding: 6px;
background: transparent;
font: inherit;
}
/* Hack to remove Safari's extra padding. Remove if you don't care about pixel-perfection. */
#media screen and (-webkit-min-device-pixel-ratio:0) {
.placeholder input, .placeholder textarea { padding: 4px; }
}
Robert Nyman discusses the problem and documents his approach in his blog.
This fiddle that has all the neccessary HTML, CSS and JS.
Unfortunately, he solves the problem by changing value.
This will not work by definition if placeholder text is itself a valid input.
I found this question by googling out the solution to the same problem. It seems that existing plugins either don't work in elder browsers or hide placeholder on focus.
So I decided to roll on my own solution while trying to combine best parts from existing plugins.
You may check it out here and open an issue if you face any problems.
How about something simple like this? On focus save out the placeholder attribute value and remove the attribute entirely; on blur, put the attribute back:
$('input[type="text"]').focus( function(){
$(this).attr("data-placeholder",$(this).attr('placeholder')).removeAttr("placeholder");
});
$('input[type="text"]').blur( function(){
$(this).attr("placeholder",$(this).attr('data-placeholder'));
});
I wrote my own css3 only solution. See if that fullfills all your needs.
http://codepen.io/fabiandarga/pen/MayNWm
This is my solution:
the input element is set to "required"
an aditional span element for the placeholder is needed. This element is moved on top of the input element (position: absolute;)
with css selectors the input element is tested for validity (required fields are invalid as long as there is no input) and the placeholder is then hidden.
Pitfall: The placeholder is blocking mouseevents to the input! This problem is circumvented by hiding the placeholder element when the mouse is inside the parent (wrapper).
<div class="wrapper">
<input txpe="text" autofocus="autofocus" required/>
<span class="placeholder">Hier text</span>
</div>
.placeholder {
display: none;
position: absolute;
left: 0px;
right: 0;
top: 0px;
color: #A1A1A1;
}
input:invalid + .placeholder {
display: block; /* show the placeholder as long as the "required" field is empty */
}
.wrapper:hover .placeholder {
display: none; /* required to guarantee the input is clickable */
}
.wrapper{
position: relative;
display: inline-block;
}
Maybe you can try with Float Label Pattern :)
See Float labels in CSS