How to prevent div of variable height from moving other elements? - css

HTML:
<div id="autocomplete" hidden></div>
<input type = "button" id = "search" value = "Search">
The autocomplete div holds various input tags generated by jQuery. When the input tags are created, they shift the button down the screen in order to fit the autocomplete content. What I want to do is to have the autocomplete div overlay on top of the the button rather than shifting the button down.
I have tried using z-index, but it seems to only work if autocomplete is placed after the button in HTML, the using negative margin to shift autocomplete back up. I don't like this solution since it messes up when viewed from other screen sizes.
Is there another way?

I think you have to use absolute positioning to keep the button over the inserting elements.
You can do something like this:
$('#autocomplete').append($('<div>').text('WOW1'))
$('#autocomplete').append($('<div>').text('WOW2'))
$('#autocomplete').append($('<div>').text('WOW3'))
$('#autocomplete').append($('<div>').text('WOW4'))
#container {
position: relative;
}
#search {
position: absolute;
top: 0;
}
#autocomplete {
padding-top: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div id="autocomplete" ></div>
<input type = "button" id = "search" value = "Search">
</div>
EDIT:
Here is a link to see how CSS position works:
https://developer.mozilla.org/en-US/docs/Web/CSS/position
Also I recommend you to check this stack overflow answer about relative vs absolute positioning it has a very natural response (Position Relative vs Absolute?)
This tells the browser that whatever is going to be positioned should
be removed from the normal flow of the document and will be placed in
an exact location on the page. It won't affect how the elements before
it or after it in the HTML are positioned on the Web page however it
will be subject to it's parents' positioning unless you override it.

This is the general method to have the items inside the autocomplete div not affect the flow of the other elements on the page (your button in this case).
#autocomplete {
position: relative;
}
#autocomplete > * {
position: absolute;
}
A few comments to improve this code:
Don't use IDs (#) on your css. Better stick to class names.
Don't use the wildcard (*) - preferably add the items that will exist inside the autocomplete, which are not shown on the question. And better, wrap them all in another element so you don't have to absolute position all of them individually

Related

CSS: prevent absolute image from extending into specific divs

Is there a way to prevent an absolutely placed image from extending into certain elements?
The reason: I allow my users to customize their websites by adding images. But it's possible for them to place the image in such a way that it covers the form buttons - then they can't remove it again.
#parent{
position:relative;
}
#my_img {
position:absolute;
# top, left can be anything
}
<div id = "parent">
<img id = "my_img" src = "my_pic.jpg" >
</div>
<div id = "other_div">
I always want to see this text regardless of my_img top and left
</div>
The determine in which order the elements of your html get laid out other than the document strucutre you need to position your element (relative, absolute or fixed) and give the element a z-index value.
Also you need to assign atleast top/bottom and left/right to positioned elements to prevent problems in older IE versions.
#other_div {
position: relative;
top: 0;
left: 0;
z-index: 1337;
}

Show a div only if URL has no fragment identifier

It's hard to explain what I mean, so see this jsfiddle first: http://jsfiddle.net/Gsggy/
When a user clicks 1, div number 1 shows, same for the others, simple enough.
However, before a user has clicked on a number, there is no div there, because it relies on the # value in the URL
How can I set a default div that is there with a blank url e.g. www.jsfiddle.com but disappears when someone clicks a number and makes it www.jsfiddle.com/#1
The thing is you can't really target an element in a way to tell it "do something while someone else is the target".
There are however some workarounds to this dilemma. One solution would be to always dispay the default content and display the target elements above.
You can use the fact that elements that appear later in the dom are usually rendered above nodes which appear earlier. So you could have for example a negative top margin or an absolute positioned element cover up your default content.
Improving on your html structure:
<div class="default" id="z">0</div>
<div id="a">1</div>
<div id="b">2</div>
<div id="c">3</div>
This css does work:
.default {
display: block;
background: #eff;
}
div + div {
margin-top: -102px;
}
div:target {
background: #eef;
display: block;
position: relative;
}
The downside to this particular approach is that you need to know the exact dimensions of your default content.
See this fiddle: http://jsfiddle.net/Gsggy/4/
use nth-of-type or last-of-type selector and make a default div in last i think it will work in your case

CSS - z-index not working properly

I'm using z-index on my page ( -link no longer needed- ), and it doesn't work properly: it doesn't place certain divs above all others...
You can see it yourself, by clicking one of the items in the left, or right bar.
Then, the mask will fade in, but show the message box, beneath it.
I've tried a lot, but I just can't get the message box to show above all others...
What can I do to fix this? [note: 2nd question below!]
If you don't want to check the page, the message box is located in some other divs:
<div>
<div>
<div>message box</div>
</div>
</div>
The CSS positioning is like this:
.window {
position: fixed;
left: 0px;
top: 0px;
z-index: 100;
}
I use position:fixed, because position:absolute is not absolute here, the div is not aligned to the body, but something else somehow.
Is there a way to reset the positioning and absolute position it again?
For as long as I can remember, z-index issues often come from the fact than the parents of the z-indexed elements are not positioned. Sibling parents should be positioned.
If you're using jquery check the top Z Index Plug In, you can apply it when the object has a mouse over event like:
<div id="modal" onmouseover="$(this).topZIndex();"></div>
Then change the position to absolute with jquery also or viceversa:
$(document).ready(function(){ $('#modal').css('position','absolute'); });
if you remove z-index from #leftbar it fixes your problem. The position should not matter, as long as you have one.

Making two spans fill a div; one span is fixed with, the other isn't?

I'm currently working on a new project. I've got a div which acts as a container "container" and inside this there are two span tags; "label" and "buttons". The buttons span tag has two links inside of it and my css changes the a tag and styles it like a button (this is okay). The buttons span tag is told to float to the left, and has a set width of 182px.
The label span tag is where the text description goes (and is has a set height, and a background colour). Essentially it should look like this:
Label : [button1 : button2]
All on a single line. The square brackets represent the fixed width of 182px.
The problem I'm having is that I can't figure out how to make "Label" take up the remaining space.
Label can't be a fixed width because I want the same element to be able to be used regardless of the size of the container (this varies between pages). But when I set it to 100% it takes up the full line and pushes the buttons onto a new line.
Ideally I'd like to be able to use some css like "100% - 182px", but I know css doesn't support this. Does anyone have any suggestions on what I could do to get this working?
<div id="container">
<span id="label"><p>song title</p></span>
<span id="buttons"><img src="resources/images/fill.gif" width="1" height="1">edit<img src="resources/images/fill.gif" width="1" height="1">delete</span>
</div>
This can be done easily with block elements.
The #label element would automatically fill the full width (no need for width:100%). If you leave a margin at the right of the element, and let #buttons floating to the right, this will do exactly what you want.
#label {
display: block;
margin-right: 100px;
}
#buttons {
width: 100px;
float: right;
}
Try this here: http://jsfiddle.net/nPBak/1/
(notice that you have to move #label after #buttons)

width:auto for <input> fields

Newbie CSS question. I thought width:auto for a display:block element meant 'fill available space'. However for an <input> element this doesn't seem to be the case. For example:
<body>
<form style='background:red'>
<input type='text' style='background:green; display:block; width:auto'>
</form>
</body>
Two questions then:
Is there a definition of exactly what width:auto does mean? The CSS spec seems vague to me, but maybe I missed the relevant section.
Is there a way to achieve my expected behavior for a input field - ie. fill available space like other block level elements do?
Thanks!
An <input>'s width is generated from its size attribute. The default size is what's driving the auto width.
You could try width:100% as illustrated in my example below.
Doesn't fill width:
<form action='' method='post' style='width:200px;background:khaki'>
<input style='width:auto' />
</form>
Fills width:
<form action='' method='post' style='width:200px;background:khaki'>
<input style='width:100%' />
</form>
Smaller size, smaller width:
<form action='' method='post' style='width:200px;background:khaki'>
<input size='5' />
</form>
UPDATE
Here's the best I could do after a few minutes. It's 1px off in FF, Chrome, and Safari, and perfect in IE. (The problem is #^&* IE applies borders differently than everyone else so it's not consistent.)
<div style='padding:30px;width:200px;background:red'>
<form action='' method='post' style='width:200px;background:blue;padding:3px'>
<input size='' style='width:100%;margin:-3px;border:2px inset #eee' />
<br /><br />
<input size='' style='width:100%' />
</form>
</div>
"Is there a definition of exactly what width:auto does mean? The CSS
spec seems vague to me, but maybe I missed the relevant section."
No one actually answered the above part of the original poster's question.
Here's the answer:
http://www.456bereastreet.com/archive/201112/the_difference_between_widthauto_and_width100/
As long as the value of width is auto, the element can have horizontal
margin, padding and border without becoming wider than its container...
On the other hand, if you specify width:100%, the element’s total
width will be 100% of its containing block plus any horizontal margin,
padding and border... This may be what you want, but most likely it isn’t.
To visualise the difference I made an example:
http://www.456bereastreet.com/lab/width-auto/
ORIGINAL answer using Angular: Because input's width is controlled by it's size attribute, this is how I initialize an input width according to its content:
<input type="text" class="form-list-item-name" [size]="myInput.value.length" #myInput>
UPDATE for JavaScript (10/01/2022): My original answer was from the time I was studying Angular. If you need pure, Vanilla JavaScript the solution is even simpler:
<input type="text" oninput="this.size = this.value.length">
Or add an "input" event listener to your input html element and run a code like this:
const myInput = document.querySelector('input');
myInput.addEventListener('input', this.typing);
(...)
typing(e) {
e.target.setAttribute('size', e.target.value.length);
}
Obs: Depending on the browser, input may restore to its default size of something between 150px and 250px if/when size gets the 0 value. In this case, just add +1 to value.length:
<input type="text" oninput="this.size = this.value.length + 1">
OR:
typing(e) {
e.target.setAttribute('size', e.target.value.length + 1);
}
As stated in the other answer, width: auto doesn't work due to the width being generated by the input's size attribute, which cannot be set to "auto" or anything similar.
There are a few workarounds you can use to cause it to play nicely with the box model, but nothing fantastic as far as I know.
First you can set the padding in the field using percentages, making sure that the width adds up to 100%, e.g.:
input {
width: 98%;
padding: 1%;
}
Another thing you might try is using absolute positioning, with left and right set to 0. Using this markup:
<fieldset>
<input type="text" />
</fieldset>
And this CSS:
fieldset {
position: relative;
}
input {
position: absolute;
left: 0;
right: 0;
}
This absolute positioning will cause the input to fill the parent fieldset horizontally, regardless of the input's padding or margin. However a huge downside of this is that you now have to deal with the height of the fieldset, which will be 0 unless you set it. If your inputs are all the same height this will work for you, simply set the fieldset's height to whatever the input's height should be.
Other than this there are some JS solutions, but I don't like applying basic styling with JS.
It may not be exactly what you want, but my workaround is to apply the autowidth styling to a wrapper div - then set your input to 100%.
If you're willing to include a little JavaScript to solve this, you can get exact sizing. This doesn't rely on approximating width with size or ems, doesn't rely on any hardcoded element widths, and works for e.g., type="number", which don't accept a size attribute.
The trick is to get your input sized exactly like a span with the same content, by actually having an invisible span with the same content.
Put your input inside a div along with a span that mirrors the input's value. Give both the input and the span the same styling, give the input 100% width, then hide the span and absolute-position the input to sit on top of the span.
This way, the container (and thus the input) are automatically sized by the visual appearance of the content of the invisible span.
https://codepen.io/spiffytech/pen/abwWRqo
<div id="relative-parent">
<span id="size-calibration"></span>
<input id="autosized-input" />
</div>
<style>
#relative-parent {
position: relative;
/* Have some width if the input is empty */
min-width: 1em;
/* Adjust size to match the span */
width: min-content;
}
#size-calibration {
visibility: hidden;
/* Prevent the span from wrapping the text when input value has multiple words, or collapsing multiple spaces into one */
white-space: pre;
}
#autosized-input {
position: absolute;
left: 0;
width: 100%;
}
#size-calibration, #autosized-input {
/* Normalize styles that the browser sets differently between spans and inputs.
Ideally, use a "CSS reset" here. */
font-family: "Arial";
padding: 0;
/* Demonstrate that this works for input with custom styles */
font-size: 24px;
}
</style>
<script>
function updateSize() {
const span = document.getElementById('size-calibration');
const input = document.getElementById('autosized-input')
span.innerText = input.value;
}
document.addEventListener('DOMContentLoaded', () => {
const input = document.getElementById('autosized-input');
input.oninput = updateSize;
// Provide some initial content
input.value = "I'm sized exactly right!"
updateSize();
})
</script>
After tried methods all above and failed, I workaround by modifying   width property in style by unit em:
tgt.style.width = `${(tgt.value.length + 1) / 2}em`
The only option I can think of is using width:100%. If you want to have a padding on the input field too, than just place a container label around it, move the formatting to that label instead, while also specify the padding to the label. Input fields are rigid.
Answer 1 - "response" gave a nice answer/link for it. To put it in short, "auto" is the default, so it is like removing any changes in the width of an element
Answer 2 - use width: 100% instead. It will fill the 100% of the parent container, in this case, the "form".
Using JQuery
$(document).on('input', '.input-fit-width', (e) => {
$(e.currentTarget).attr('size',e.currentTarget.value.length);
})
Nowdays, flex or grid makes it much easier , it overrides default style/behaviors of https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#size which has a default value set at 20 see : https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#size
Giving you 2 plain CSS options without requiring JavaScript nor setting width to 100% and deal with box-sizing.
flex/flex-grow
<form style='background:red;display:flex;'>
<input type='text' style='background:green; flex-grow:1'>
</form>
grid
<form style='background:red;display:grid;'>
<input type='text' style='background:green;'>
</form>
Jquery way of adjusting size of input automatically.
In general:
$('#my_input_id').width( ($('#my_input_id').val().length) + "ch" );
On text input:
$(document).on("input", '#my_input_id', function () {
$(this).width( ($(this).val().length) + "ch" );
});
I think the simplest solution is to set parent element's width:
form{
width: 100%!important;
}

Resources