Whitespace control in Twig templates allows you to control the indentation
and spacing of the generated contents (usually HTML code). Most of the times you
should ignore this feature, because the HTML contents are minified and
compressed before sending them to the users, so trying to generate perfectly
aligned HTML code is just a waste of time.
However, there are some specific cases where whitespace can change how things
are displayed. For example, when an <a>
element contains white spaces after
the link text and the link displays an underline, the whitespace is visible.
That's why Twig provides multiple ways of controlling white spaces. In recent
Twig versions, we've improved those features.
New whitespace trimming options
Consider the following Twig snippet:
| <ul><li>{%ifsome_expression%}{{some_variable}}{%endif%}</li></ul> |
If the value of some_variable
is 'Lorem Ipsum'
, the HTML generated when
the if
expression matches, would be the following:
| <ul><li>
Lorem Ipsum</li></ul> |
Twig only removes by default the first \n
character after each Twig tag
(the \n
after the if
and endif
tags in the previous example). If
you want to generate HTML code with better indention, you can use the -
character, which removes all white spaces (including newlines) from the left
or right of the tag:
| <ul><li>{%- ifsome_expression%}{{-some_variable -}}{%endif -%}</li></ul> |
The output is now:
| <ul><li>Lorem Ipsum</li></ul> |
Starting from Twig 1.39 and 2.8.0, you have another option to control
whitespace: the ~
character (which can be applied to {{
, {%
and{#
). It's similar to -
, with the only difference that ~
doesn't
remove newlines:
| <ul><li> {%~ if some_expression %}{{some_variable -}}{%endif~%}</li></ul> |
The output now contains the newlines after/before the <li>
tags, so the
generated HTML is more similar to the original Twig code you wrote:
| <ul><li>
Lorem Ipsum</li></ul> |
Added a spaceless filter
In previous Twig versions, there was a tag called {% spaceless %}
which
transformed the given string content to remove the white spaces between HTML
tags. However, in Twig, transforming some contents before displaying them is
something done by filters.
That's why, starting from Twig 1.38 and 2.7.3, the spaceless
tag has been
removed in favor of the spaceless
filter, which works exactly the same:
| {{some_variable_with_HTML_content|spaceless}} |
However, this is commonly used with the alternative way of applying some filter
to some HTML contents:
| -{% spaceless %}+{% apply spaceless %}
{# some HTML content here #}-{% endspaceless %}+{% endapply %} |
In case you missed it, the apply
tag was recently added to replace the
previous filter
tag.
In any case, even after these changes, it's still recommend to not use thespaceless
filter too much. The removal of white spaces with this filter
happens at runtime, so calling it repeatedly can hurt performance.
Fine-grained escaping on ternary expressions
This new feature introduced in Twig 1.39 and 2.8 is not related to whitespace
control, but it's an important new feature to consider in your templates.
Consider the following example and the results rendered in Twig versions before
1.39 and 2.8:
| {%setfoo='<strong>foo</strong>'%}{%setbar='<strong>bar</strong>'%}{{false?'<strong>bar</strong>':foo|raw}}{# renders as '<strong>foo</strong>' #}{{false?bar:foo|raw}}{# renders as '<strong>foo</strong>' #}{{(false?bar:foo)|raw}}{# renders as '<strong>foo</strong>' #} |
The reason why this example worked in that way in previous Twig versions is that
in the first ternary statement, foo
is marked as being safe and Twig does
not escape static values. In the second ternary statement, even if foo
is
marked as safe, bar
remains unsafe and so is the whole expression. The third
ternary statement is marked as safe and the result is not escaped.
This behavior was confusing to lots of designers and developers. That's why,
starting from Twig 1.39 and 2.8, the result of this example has changed as follows:
| {%setfoo='<strong>foo</strong>'%}{%setbar='<strong>bar</strong>'%}{{false?'<strong>bar</strong>':foo|raw}}{{false?bar:foo|raw}}{{(false?bar:foo)|raw}}{# renders as '<strong>foo</strong>' in all cases #} |