Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does setting the element display property to flex in CSS change the behaviour of the JS onclick event with 'event.target'?

Tags:

javascript

css

I have a basic list going on, with the HTML structure like this:

<ul class="list">
{...}
  <li class="item">Ellipse</li>
{...}

Then I use some JS to add buttons to delete items, so the end structure is like this:

<ul class="list">
{...}
  <li class="item">Ellipse <button>Delete item</button></li>
{...}

I also have a function to strike through the list elements on click by toggling a CSS class:

let ul = document.querySelector('.list');
{...}

function markAsDone (event) {  
  let target = event.target;
  target.classList.toggle('done');
}
{...}

ul.addEventListener('click', markAsDone);

This works as expected (e.g. the list item is struck through). However, if I change the list items' display property to flex in CSS:

.item {
  display: flex;
  justify-content: space-between;
  max-width: 300px ;
}

And then click on the item, the text of the button also is struck through, unlike before! Since I've started writing this, I no longer know which behaviour feels more 'wrong' to me, lol.

The full code is on Codepen here. Try clicking the items in the list, then uncomment the CSS style for .item to see what I mean.

My uneducated guess would be that the answer to this is in the way the flex containers treat the items in them. However, my understanding of it is very limited, so I've come to you for an answer.

like image 325
Kekuy Avatar asked Mar 12 '20 10:03

Kekuy


People also ask

What is Flex used for in CSS?

The flex CSS shorthand property sets how a flex item will grow or shrink to fit the space available in its flex container.

Can we use Onclick in CSS?

To use CSS onClick, you'll essentially need to create a pseudo class. You'll use CSS selectors and the checkbox hack to produce something like an OnClick function. And you can get away with this if you just want to use only CSS to make some minor changes, like border width or border radius.

What are the Display properties in CSS?

The display CSS property sets whether an element is treated as a block or inline element and the layout used for its children, such as flow layout, grid or flex. Formally, the display property sets an element's inner and outer display types.


2 Answers

Simply wrap your text with span will resolve your issue. check below snippet.

i am not sure but you apply done class to parent element which strike through both element.

let button = document.querySelector('.smash');
let input = document.querySelector('.userinput');
let ul = document.querySelector('.list');
let listItems = document.querySelectorAll('.list > li');

function inputLengthValue() {
  let result = input.value.length;
  return result;
}

function createListElem() {
  let li = document.createElement('li');
  li.appendChild(document.createTextNode(input.value));
  li.classList.add('item');
  ul.appendChild(li);
  input.value = "";

  let delButton = document.createElement('button');
  delButton.appendChild(document.createTextNode('Delete item'));
  li.appendChild(delButton);
  delButton.addEventListener('click', removeItem)
}

function addListItemOnclick() {
  if (inputLengthValue() != 0) {
    createListElem();
  }
}

function addListItemOnEnterPress(event) {
  if (inputLengthValue() != 0 && event.keyCode === 13) {
    createListElem();
  }
}

function createDeleteButtons() {
  for (let i = 0; i < listItems.length; i++) {
    let delButton = document.createElement('button');
    delButton.appendChild(document.createTextNode('Delete item'));
    listItems[i].appendChild(delButton);
    delButton.addEventListener('click', removeItem);
  }
}

function markAsDone(event) {
  let target = event.target;
  target.classList.toggle('done');
}

function removeItem(event) {
  let target = event.target;
  target.parentNode.remove();
}


button.addEventListener('click', addListItemOnclick);
input.addEventListener('keydown', addListItemOnEnterPress);
ul.addEventListener('click', markAsDone);
createDeleteButtons(); // create delete btn for default items
.done {
  text-decoration: line-through;
}

.item {
  display: flex;
  justify-content: space-between;
  max-width: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 class="title">Some list</h1>
<input type="text" placeholder="enter your text" class="userinput">
<button class="smash">Add item</button>
<ul class="list">
  <li class="item"><span>Romboid</span></li>
  <li class="item"><span>Square</span></li>
  <li class="item"><span>Circle</span></li>
  <li class="item"><span>Ellipse</span></li>
  <li class="item"><span>Rectangle</span></li>
  <li class="item"><span>Oval</span></li>
</ul>
like image 136
Sumit Patel Avatar answered Sep 29 '22 21:09

Sumit Patel


To answering "WHY" let's have a look at the specification.

The 'text-decoration' property on descendant elements cannot have any effect on the decoration of the ancestor.

Your code is fine. This behavior is consistent with spec, text-decoration affect all children (with some exceptions). There is only one thing you can do about it: just try to avoid the text-decoration on the parent element, if you doт't want this text-decoration to be applied to the children.

Note that text decorations are not propagated to floating and absolutely positioned descendants, nor to the contents of atomic inline-level descendants such as inline blocks and inline tables.

Buttons are display: inline-block; by default, that's why they look fine unless the parent container takes control over it, such as flex or grid.

Here is an example:

.item {
  font-size: 20px;
  padding: 10px;
  border: 1px solid green;

  text-decoration: line-through;
  text-decoration-color: red;
}

.item-flex { display: flex; }
.item-inline-flex { display: inline-flex; }

.item-grid { display: grid; }
.item-inline-grid { display: inline-grid; }

.item-table { display: table; }
.item-inline-table { display: inline-table; }

.item-inline { display: inline; }
.item-inline-block { display: inline-block; }

.item span, .item button {
  margin-left: 10px;
  text-decoration: overline underline;
  text-decoration-color: blue;
}
<div class="item">
  display:
  <span>block</span>
  <button>button</button>
</div>

<div class="item item-flex">
  display:
  <span>flex</span>
  <button>button</button>
</div>

<div class="item item-grid">
  display: <span>grid</span>
  <button>button</button>
</div>

<div class="item item-table">
  display:
  <span>table</span>
  <button>button</button>
</div>

<div class="item item-inline">
  display:
  <span>inline</span>
  <button>button</button>
</div>

<div class="item item-inline-block">
  display:
  <span>inline-block</span>
  <button>button</button>
</div>

<div class="item item-inline-flex">
  display:
  <span>inline-flex</span>
  <button>button</button>
</div>

<div class="item item-inline-grid">
  display:
  <span>inline-grid</span>
  <button>button</button>
</div>

<div class="item item-inline-table">
  display:
  <span>inline-table</span>
  <button>button</button>
</div>
like image 40
artanik Avatar answered Sep 29 '22 21:09

artanik