How to use position of relative?
I have created a todo-apps with js but I have one problem : my button doesn’t move when I add some other task to do While I give it a position of relative. This is my CSS code:
button { border-radius: 5px; margin-left: auto; margin-right: auto; position: relative; }
This is my HTML code
<h1>To Do List</h1> <input type="text" placeholder="Name..." id="Name"> <input type="button" id="addItem" value="Add Item" /> <div class="choices"> <p id="p"></p> <button id="btn" type="submit"> Clear Items</button> </div> <script type="text/javascript" src="main.js"></script> </body> </html>
First do some reading on ‘stacking context’ (e.g. MDN: The stacking context and MDN: Stacking without the z-index property) as it is important to understand what layering elements (or ‘stacking’) in a document encompasses.
For your problem, remember this: a container holding 1 to N child elements (in your case ‘.choices’ with 1 button) has to be position: relative
and its child elements position: absolute
with (optionally) their positioning values set (top, right,left,bottom
).
So, when you want the ‘Clear Items’ button to stick to the bottom of the TODO-list you need at least:
.choices { position: relative; /* makes child elements move relative to this parent */ } button { position: absolute; /* move this element absolute within parent */ bottom: 0.5rem; /* position just above parent bottom */ }
The example snippet:
.choices { position: relative; /* makes child elements move relative to this parent */ /* DEMO */ padding-bottom: 1.5rem; /* create some bottom space below button */ background-color: Linen; } #btn { position: absolute; /* move this element absolute within parent */ bottom: 0.5rem; /* position just above parent bottom */ border-radius: 5px; /* to horizontally center within parent */ left: 50%; /* move child to center of parent */ transform: translateX(-50%); /* move half size of child back */ }
<h1>To Do List</h1> <input type="text" placeholder="Name..." id="Name"> <input type="button" id="addItem" value="Add Item" /> <div class="choices"> <p id="p"></p> <p>1 Lorem ipsum dolor sit amet</p> <p>2 Lorem ipsum dolor sit amet</p> <p>3 Lorem ipsum dolor sit amet</p> <p>4 Lorem ipsum dolor sit amet</p> <button id="btn" type="submit">Clear Items</button> </div>
HOWEVER
In your construction you made the ‘Clear Items’ button part of the javascript output container, which is logically incorrect. ‘action buttons’ are not part of the content itself and need their own container (obviously they can be over/under content, but are not part of the content, your ‘TODO-items’, itself).
By having split the functionality (input, output, actions) it now no longer matters how you modify the ‘output’ with Javascript, the ‘actions’ stay below the content.
Below an example snippet showing how I would structure your TODO panel with ‘flexbox layout’.
Generic code (at least required):
.flexbox-panel { display: flex; justify-content: space-between; } .user-input { ... } /* user entry field and button */ .js-todo-output { flex-grow: 1 } /* the TODO-items */ user-action-buttons { ... } /* the action button(s) */
This way it does not matter how many items there are in the list, the action button stays below them.
Second snippet with ‘Flexbox Layout’ alternative:
.flexbox-panel { display: flex; flex-direction: column; justify-content: space-between; } .flexbox-panel>* { width: 100%; padding: 0.5rem; /* some nice inner spacing */ } .user-input { } /* user entry field and button */ .js-todo-output { flex-grow: 1 } /* the TODO-items */ .user-action-buttons { } /* the action button(s) */ .js-todo-output, .user-action-buttons { background-color: Linen; } .act-button { display: block; margin: 0 auto } /* default is 'inline', needs to be 'block' for margin to work */ /* for easy debugging (put in <body>) */ [outlines="1"] * { outline: 1px dashed } /**************************/ /* preferred global rules */ /**************************/ html,body { box-sizing: border-box; width: 100%; max-width: 100% } *::before,*::after, * { box-sizing: inherit } body { margin: 0; /* remove HTML default body spacing */ /* responsive page padding with 'linear equation y=mx+b' p1(320,32) p2(1920, 72) => 0.025x + 24 p3(320, 8) p4(1920,320) => 0.195x - 54.4 On an 320px display the T/B space is 32px and the L/R space 8px On an 1920px display the T/B space is 72px and the L/R space 320px All other values for all other display sizes are calculated. math reference: https://www.mathsisfun.com/equation_of_line.html */ padding: calc(2.5vh + 24px) calc(19.5vw - 54.4px); }
<body outlines="0"> <div class="flexbox-panel"> <h1>To Do List with flexbox</h1> <div class="user-input"> <input type="text" placeholder="Name..." id="Name"> <input type="button" id="addItem" value="Add Item" /> </div> <div class="js-todo-output"> <p>1 Lorem ipsum dolor sit amet</p> <p>2 Lorem ipsum dolor sit amet</p> <p>3 Lorem ipsum dolor sit amet</p> <p>4 Lorem ipsum dolor sit amet</p> </div> <div class="user-action-buttons"> <button class="act-button" type="submit">Clear Items</button> </div> </div> </body>
EXTRA
I have inserted a few of my preferred global rules into the second snippet (commonly accepted defaults) and also show how you can use some math to create ‘responsive sizing’ in your webpage (with math reference MathIsFun: equation of a straight line).
This is because you set position related to ‘choices’ class.
Set position related to HTML page.
you must also provide an offset with:
top: 5px;
for example. Other attributes can be : bottom, right, left.
button move out the div.choices And wrap the button in another div.