Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extra Blank Spaces Between Elements In Rendered Template #7701

Closed
dsanders11 opened this issue Feb 23, 2018 · 9 comments
Closed

Extra Blank Spaces Between Elements In Rendered Template #7701

dsanders11 opened this issue Feb 23, 2018 · 9 comments

Comments

@dsanders11
Copy link

dsanders11 commented Feb 23, 2018

Version

2.5.13

Reproduction link

https://jsfiddle.net/aoxo2rod/8/

Steps to reproduce

Run the JSFiddle

What is expected?

The background should be green, styled by ul:empty, as the children of ul are all conditionally not rendered: empty v-for and v-if that evaluate to false.

What is actually happening?

The background is red, ul:empty is not used because there is a blank space inside the ul tags, which CSS doesn't consider to be :empty.


The multiple children elements are important, a single li element with v-if="false" will produce the correct result. It appears Vue is putting a blank space between the elements, even if they are conditionally not rendered (appearing as <!----> instead). It's worth noting that if you manually remove the extra spaces using developer tools, everything looks as expected, <!----> does not affect :empty.

Furthermore, this only reproduces if there is a newline between the elements. Modifying the provided JSFiddle to only have the two li with v-if="false" will produce the correct result if there's no newline between them. So Vue seems to be turning the newline between the elements into a single space, which is causing the issue.

@dsanders11 dsanders11 changed the title Extra Blank Space In Rendered Template Extra Blank Spaces Between Elements In Rendered Template Feb 23, 2018
@Justineo
Copy link
Member

Currently there is an option called preserveWhitespace for Vue Loader so you can choose to strip “empty” text nodes when using single file components. It's actually an option for vue-template-compiler but AFAIK it's not exposed as a runtime API (yet).

@posva
Copy link
Member

posva commented Feb 23, 2018

The same thing happens with regular html and empty lines, the css does not apply:

<ul>
</ul>

If you want to have no spaces you can, however, remove any white spaces in the template:

<ul><li v-for="item in items">
  <span>{{ item }}</span>
</li><li v-if="false"></li><li v-if="false"></li></ul>

Not closing because I'm not sure about the new line being replaced by an empty space but to me, this behaviour is more consistent than automatically removing whitespaces as using newlines in regular HTML would yield the same result

@dsanders11
Copy link
Author

If you want to have no spaces you can, however, remove any white spaces in the template:

That's not really a practical solution, though. Putting everything on one line turns it into an unreadable mess for anything more than the most trivial of templates.

Not closing because I'm not sure about the new line being replaced by an empty space but to me, this behaviour is more consistent than automatically removing whitespaces as using newlines in regular HTML would yield the same result

But Vue does collapse everything inside the ul into a single line, it's already chomping the newlines, it's just turning them into spaces instead. If it wants to preserve newlines, then sure, that would be consistent with how vanilla HTML acts, but it doesn't currently do that, and as such the results are unintuitive.

@Justineo, using preserveWhitespace does seem to get the intended result, but as you said, it's only available via vue-loader at the moment. Is there any way to activate this for a single node? It's a bit icky to have to turn it on for an entire project if you only want that behavior for a single template, or even just a single part of a single template. It'd be great if there was a directive like v-preserve-whitespace="false" that could be used on an individual node. I briefly looked at writing my own directive to get that end result, but the only reasonable hook to use seemed to be componentUpdated and changing the element's innerHTML at that point led to inconsistent results, it's probably not a good place to touch the HTML.

@Justineo
Copy link
Member

Is there any way to activate this for a single node?

Like Evan said here (except that this might not be solved by CSS), I think it's better that we keep it consistent across the whole project. Custom directives may work if you just remove whitespace-only text nodes instead of setting innerHTML directly.

@dsanders11
Copy link
Author

Like Evan said here (except that this might not be solved by CSS), I think it's better that we keep it consistent across the whole project.

That doesn't really work for reusable components, a library can't (or at least shouldn't) force users to change project-wide settings. It's also not applicable if they're not using vue-loader, at the moment.

Custom directives may work if you just remove whitespace-only text nodes instead of setting innerHTML directly.

You're right, that seemed to make it work nicely. Example directive below for anyone who comes across this looking for a solution:

function trimEmptyTextNodes (el) {
  for (let node of el.childNodes) {
    if (node.nodeType === Node.TEXT_NODE && node.data.trim() === '') {
      node.remove()
    }
  }
}

Vue.directive('trim-whitespace', {
  inserted: trimEmptyTextNodes,
  componentUpdated: trimEmptyTextNodes
})

So the open question remains regarding Vue chomping the newlines into a single space. Is there a rationale for this behavior? If it chomped the newlines into nothing, rather than a single space, this would work out of the box.

@Justineo
Copy link
Member

Collapsing new lines and white spaces is consistent with the behavior of HTML.

@yyx990803
Copy link
Member

yyx990803 commented Mar 10, 2018

HTML renders any consecutive whitespaces (including newlines and everything) as a single space. So chomping consecutive whitespaces into a single space results in the exact same render output while reducing the payload. This is intended and is in fact consistent with what you'd expect when styling plain HTML with CSS.

@lazarljubenovic
Copy link

@yyx990803 Unless you use <pre> tag (or, in general, white-space: pre-wrap;).

@Mushr0000m
Copy link

I agree that a way to disable (on demand like a directive or something else) newline to space transform may be realy usefull. The template code would still look nice and indented but would fix a major issue when working with inline element in css.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants