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

Invisible node removal: preheaders and responsive design #252

Closed
sanderkruger opened this issue Oct 12, 2015 · 8 comments · Fixed by #737
Closed

Invisible node removal: preheaders and responsive design #252

sanderkruger opened this issue Oct 12, 2015 · 8 comments · Fixed by #737
Assignees
Milestone

Comments

@sanderkruger
Copy link
Contributor

Invisible node removal is nice but it creates problems for 2 cases: preheaders and responsive design.

Preheaders are hidden paragraphs at the start of an email to force a digest of the email to show a certain text. When an email is nicely designed with some links at the top or the subject repeated as a header, this is not the most important content you want recipients to see in the email list of their email client. Most email clients show the first 80-something readable characters of an email.

Typically, you put a <span class="preheader">blablabla</span> as the first element in the body and attach display:none, font-size=1px and some other styles to it to make sure it's hidden.

It would be good to be able to exclude certain selectors from invisible node removal.

The second issue is with responsive design. You may want to have 2 alternative representations in the document, by default one is shown and the other is hidden. A media query hides the one and shows the other.

invisible node removal should check media queries to see if a hidden node might be shown under certain circumstances.

One interesting way to handle both cases and open a route to more generic control over emogrifier is to introduce emogrifier classes. The idea is that by applying a class to a DOM element, that element gets special treatment from emogrifier. For example:

<span class="emogrifier-show preheader">My preheader</span>

Emogrifier would see the class and keep the node, despite being a candidate for invisible node removal. The emogrified result HTML would remove all classes starting with emogrifier-.

@oliverklee
Copy link
Contributor

Sounds good! 👍

@oliverklee
Copy link
Contributor

@jjriv, @zoliszabo I'd like to completely remove the removal of invisible nodes. Minifying the HTML should not be the job of Emogrifier, but the job of the person/component creating the input HTML in the first place, and removing those nodes is tricky. Thoughts?

@oliverklee oliverklee added this to the 3.0.0 milestone Jan 7, 2018
@zoliszabo
Copy link
Contributor

Since the feature is already implemented, instead of removing it, wouldn't it be better to only change the default behavior to not remove invisible nodes by default?

Secondly, the current option flag name is not OK: it does exactly the opposite to how it is called.

if ($this->shouldKeepInvisibleNodes) {
$this->removeInvisibleNodes($xPath);
}
(PR #472)

@oliverklee
Copy link
Contributor

I find it very important that we have the courage to remove code or features once it does not provide enough benefit anymore or creates problems which are not easily solvable. Every line of code is a line we need to maintain and test.

If I read @sanderkruger's comment correctly, the removal of invisible nodes creates problems as the nodes might not stay hidden or might be needed for other purposes than being visible.

As the removal of (hopefully) invisible nodes has the only purpose of reducing the HTML size, we can remove this feature without any visible problems, while avoiding the problems this feature brings.

Removing unneeded elements should be the responsible of the client providing the HTML or some other class/tool that comes after Emogrifier has inlined the CSS.

@jjriv
Copy link
Contributor

jjriv commented Jan 8, 2018

I agree with deprecating this feature. Emogrifier has one purpose, and that is not to minimize or alter the payload.

@oliverklee oliverklee modified the milestones: 3.0.0, 4.0.0, 2.1.0 Jan 10, 2018
@oliverklee
Copy link
Contributor

So we'll deprecate this feature and move it to a separate class.

jjriv pushed a commit that referenced this issue Jan 10, 2018
@JakeQZ
Copy link
Contributor

JakeQZ commented Sep 28, 2019

This should be straightfoward to implement - we can just modify the XPath in HtmlPruner::DISPLAY_NONE_MATCHER to exclude elements with a specific class.

For the class name, I would suggest a vendor prefix is approprate, and 'keep' or perhaps 'do not remove' is more descriptive than 'show', so we'd have class="-emogrifier-keep" or perhaps class="-emogrifier-do-not-remove".

The class would be automatically removed by HtmlPruner::removeRedundantClassesAfterCssInlined() (or HtmlPruner::removeRedundantClasses()) if invoked after removeElementsWithDisplayNone() (which is the logically more optimal order anyway). So I would suggest that users would need to invoke one of these methods in order to have the class removed, rather than us implement duplicate functionality in removeElementsWithDisplayNone() to do this.

@oliverklee, @zoliszabo, Does this seem reasonable?

@oliverklee
Copy link
Contributor

Sounds good. (I'd prefer "keep" over "not remove".)

@JakeQZ JakeQZ self-assigned this Sep 28, 2019
JakeQZ added a commit that referenced this issue Sep 28, 2019
The additional part of the XPath expression was obtained by running
`:not(.-emogrifier-keep)` through `CssSelectorConverter::toXPath()`.  It tests
for attribute presence before checking the value, presumably as an omptimization
to avoid unnecessary processing of a null/empty value.  On the presumed basis
that this is a good idea, a similar check has been added for the `style`
attribute.

Resolves #252.
oliverklee pushed a commit that referenced this issue Sep 29, 2019
The additional part of the XPath expression was obtained by running
`:not(.-emogrifier-keep)` through `CssSelectorConverter::toXPath()`.  It tests
for attribute presence before checking the value, presumably as an optimization
to avoid unnecessary processing of a null/empty value.  On the presumed basis
that this is a good idea, a similar check has been added for the `style`
attribute.

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

Successfully merging a pull request may close this issue.

5 participants