As soon as I started coding responsive emails, I noticed that contiguous images (all with the same original height) in a HTML table row didn't always remain the same height when being responsively scaled. That's a big problem for me because the email layouts that I am working on are image heavy and have to be tightly aligned. Uneven height images break the layout. I eventually came up with the solution presented here: http://am-samples.gear.host/iPhone5S-iO7-issue.html
Navigate to that URL and resize the browser to see the responsive scaling in action.
Here are the main snippets in case you can't navigate to the URL above:
Table that has the contiguous images
<table class="100p" width="100%" cellspacing="0" cellpadding="0" border="0" align="center" bgcolor="#7fff00" style="background-color: #7fff00;">
<tr>
<td class="100p" align="center" width="100%" valign="top">
<div>
<table class="100p" width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td class="100p" width="100%" align="left" valign="top">
<span width="26.09375%" style="width: 26.09375%; display: inline-block;">
<img id="ourStory" class="responsiveImage" src="http://am-samples.gear.host/images/bottom-our-story.png" border="0" style="display: block;" />
</span><span width="19.6875%" style="width: 19.6875%; display: inline-block;">
<img id="recipes" class="responsiveImage" src="http://am-samples.gear.host/images/bottom-recipes.png" border="0" style="display: block;" />
</span><span width="25.15625%" style="width: 25.15625%; display: inline-block;">
<img id="seafood" class="responsiveImage" src="http://am-samples.gear.host/images/bottom-seafood.png" border="0" style="display: block;" />
</span><span width="29.0625%" style="width: 29.0625%; display: inline-block;">
<img id="giftCards" class="responsiveImage" src="http://am-samples.gear.host/images/bottom-giftcards.png" border="0" style="display: block;" />
</span>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
CSS classes referenced
.responsiveImage {
max-width: 100% !important;
width: 100% !important;
height: auto !important;
border: none;
}
*[class="100p"] {
width: 100% !important;
height: auto !important;
}
I've stripped the code down to the essentials just to clearly present the issue. If you take a look at the source code, you'll see that the top and bottom black strips are just tables with a black background color. The red strip is actually made up of contiguous images. The original height of all the images is the same. Because of that I expected the height of all the images to scale equally. The table that contains the images has a background color of florescent green. That way, in Litmus, it is easy to see if the height of any of the images is different.
I've tested this solution in Litmus and it works fine on the email clients that I am interested in except two: iPhone 5S (iOS7 and iOS8). Here is a screenshot of the result in iPhone 5S and iOS7 (iOS 8 produces a similar result) : http://am-samples.gear.host/images/iPhone5S-iOS7-issue.jpg
So the problem is that when scaling, sometimes the image heights are not all equal. Any ideas on how to fix this on the iPhone 5S?
Different widths with the same height makes the images a different scale, which means that as they shrink through the 100% w x auto h, they will differ in height.
To retain consistent height/width through mobile I would make sure that the scale is identical. E.g. make all images 100px x 50px. (you can use percents here if you wish too)
The only other option I can really offer from what I see is a defined height to force each to that amount, but in HTML email, this is not likely to be followed by the email clients processors.
Related
I have some design requirements for an email template where I have two "challenges":
two columns need to flip to one column
some visible border lines need to be switched from vertical to horizontal
The following shows how it should look (2 columns on the left for desktop, 1 column on the right for mobile):
The whole email is based on responsive tables and the two-column part is implemented as follows right now:
<table cellpadding="5" cellspacing="0"
style="background-color:#F6F6F6; font-size: 14px; color:#58595b; width:100%; border-collapse:collapse;">
<tr><td align="center" valign="top" height="10" colspan=2 style="line-height: 10px; font-size: 10px;"> </td></tr>
<tr>
<td valign="top" style="border-right: 1.5px solid; border-color: #d0d0d0; padding-right:40px; text-align:right; width:42%; vertical-align:top;">
Start point
</td>
<td valign="top" style="padding-left:40px; vertical-align:top;">
<strong>Fri, January 12, 2023 12:00</strong>
<br />
Harbour, Seatown
</td>
</tr>
<tr><td align="center" valign="top" height="10" colspan=2 style="line-height: 10px; font-size: 10px;"> </td></tr>
<tr>
<td valign="top" style="border-right: 1.5px solid; border-color: #d0d0d0; padding-right:40px; text-align:right; width:42%; vertical-align:top;">
End point
</td>
<td valign="top" style="padding-left:40px; vertical-align:top;">
<strong>So, January 18, 2023 10:00</strong>
<br />
Central Station, Capital
</td>
</tr>
<tr><td align="center" valign="top" height="10" colspan=2 style="line-height: 10px; font-size: 10px;"> </td></tr>
</table>
I tried the approach with having a left and a right table (explained here) but the problem is that I do not use fixed widths.
How could I achieve the required design with a responsive mail template?
You will need to use the technique as outlined in the link, but if you want to use percentages instead of fixed widths, then use width="50%".
This is because the technique works on the basic fundamentals of HTML, that if a block doesn't fit in the space available, it will automatically shift underneath.
So to enable the stacking without a fixed pixel width, you will need to add a #media query to force the stacking (otherwise it would not stack).
e.g.
#media (max-width: 620px)
.table-left,.table-right {
width: 100% !important;
}
(The article you link to is a bit outdated: don't use [class=...], just write it out normally. Gmail may strip the entire <style> section if it doesn't like something in it, and this is one of those things it doesn't like.)
I prefer an override (max-width, and !important) because you want everything possible inline, and only to use embedded styles where strictly necessary.
But that's also why it's best to use a fixed pixel width, because some email clients do not respect your embedded styles (styles in the <head>). GANGA emails (one form of Gmail account) fall into this category. Those email clients would not stack even though they may need to, if you fully rely on the #media query for the stacking.
To override the border, put a style on the <td>, and reference it in the #media query, e.g.
#media (max-width: 620px)
.border {
border-right:none!important;
}
.border-top {
border-bottom:1.5px solid #d0d0d0 !important;
}
As one doesn't have the same border structure (they don't both need border-bottom), one of the <td>s will need a different class. Here, I'm expecting the first one, i.e. <td class="border border-top">.
I'm trying to create a pricing recap at the end of a document I'm working on. I would like it to have a dotted line between the item on the left and the price on its right, very much like this :
However, this Index is generated with the createIndex function and I don't have the source HTML for this. And I've been trying since yesterday with differente HTML syntaxes to make it work but it is impossible. My best attempt so far is this one, but I can't automatically set the width of the dotted line :
<table style="width:100%;border-collapse: collapse;">
<tr>
<td style="width:40%;white-space:nowrap;">Item 1</td>
<td style="border-bottom:dotted 1px black;width:45%;"></td>
<td style="text-align:right;width:15%;white-space:nowrap;">Price 1€ HT</td>
</tr>
</table>
I really am stuck here, any advice would be welcome.
In this case you can use a little 'hack'. Unset the width of both texts (resolves to width: auto;) and set the width of the dotted line container to width: 99%;. For this to work you also need to set white-space: nowrap on the text elements, but you already did that.
<table style="width:100%;border-collapse: collapse;">
<tr>
<td style="white-space:nowrap;">Item 1</td>
<td style="border-bottom:dotted 1px black;width:99%"></td>
<td style="text-align:right;white-space:nowrap;">Price 1€ HT</td>
</tr>
</table>
I have an HTML email laid out with tables:
<table class='top-level' cellpadding="0" cellspacing="0" border="0"
width="630" height="717" bgcolor='#ffffff' style="width:630px;
height:717px; background-color: white; background: white;
border-collapse:collapse; mso-table-lspace:0pt; mso-table-rspace:0pt;">
<tr>
<td class='image-container' id="FOOBAR" valign="top" width="630"
style="width:630px !important; background-color: #DEE7F5;
background-image: -webkit-linear-gradient(left, #b6cae8, #ffffff);
background-image: -moz-linear-gradient(left, #b6cae8, #ffffff);
background-image: -o-linear-gradient(left, #b6cae8, #ffffff);
background-image: linear-gradient(#b6cae8, white); background:
linear-gradient(#b6cae8, white);">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:630px;">
<v:fill type="gradient" color="#ffffff" color2="#b6cae8" />
<v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0">
<![endif]-->
<div><table><!-- stuff --></table></div>
<!--[if gte mso 9]>
</v:textbox>
</v:rect>
<![endif]-->
</td>
</tr>
</table>
This works perfectly in Outlook 2007/10/13, as well as all the other clients I care about, EXCEPT for Outlook 2016 (Windows version). In Outlook 2016, the td.image-container element displays at only about 2/3 of the expected width. When I check out the HTML (by saving the message as HTML), it shows that the widths I set in the style attributes are in pt units and the relationship between the Outlook value and my original value isn't clear. The reformatting also strips my class and my id.
The width attribute seems to get set to the pixel value equal to the point value in the style attribute. Because the style width is set in points even on elements without a width attribute, I assume that it's the style value adjusting the width value.
How can I make sure my original width is respected?
<html xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
xmlns="http://www.w3.org/TR/REC-html40">
<head>...</head>
<body bgcolor=white lang=DE link="#497CBE" vlink="#497CBE" style='tab-interval:
35.4pt' alink="#497cbe">
<div class=WordSection1>
<table class=MsoNormalTable border=0 cellspacing=0 cellpadding=0 width=945
style='width:472.5pt;background:white;border-collapse:collapse;mso-yfti-tbllook:
1184;mso-padding-alt:0cm 0cm 0cm 0cm'>
<tr style='mso-yfti-irow:0;mso-yfti-firstrow:yes;mso-yfti-lastrow:yes'>
<td width=630 valign=top style='width:315.0pt;background:#DEE7F5;
padding:0cm 0cm 0cm 0cm'>
<p class=MsoNormal><!--[if mso & !supportInlineShapes & supportFields]><span
style='font-size:10.5pt;font-family:"Arial",sans-serif;mso-fareast-font-family:
"Times New Roman"'><span style='mso-element:field-begin;mso-field-lock:yes'></span><span
style='mso-spacerun:yes'> </span>SHAPE <span
style='mso-spacerun:yes'> </span>\* MERGEFORMAT <span style='mso-element:
field-separator'></span></span><![endif]--><span style='font-size:10.5pt;
font-family:"Arial",sans-serif;mso-fareast-font-family:"Times New Roman"'>
<!-- This linebreak added for readability; the conditional tag below was originally directly after the previous span tag -->
<!--[if gte vml 1]><v:rect
id="_x0000_s1026" style='width:315pt;height:730.7pt;mso-left-percent:-10001;
mso-top-percent:-10001;mso-position-horizontal:absolute;
mso-position-horizontal-relative:char;mso-position-vertical:absolute;
mso-position-vertical-relative:line;mso-left-percent:-10001;
mso-top-percent:-10001' stroked="f">
<v:fill color2="#b6cae8" type="gradient"/>
<v:textbox style='mso-fit-shape-to-text:t' inset="0,0,0,0">
<![if !mso]>
<!-- doesn't matter --><![endif]>
<div>
<table class=MsoNormalTable border=0 cellspacing=0 cellpadding=0
width=945 style='width:472.5pt;border-collapse:collapse;mso-yfti-tbllook:
1184;mso-padding-alt:0cm 0cm 0cm 0cm'>
<!-- table stuff -->
</table>
<p class=MsoNormal><span style='mso-fareast-font-family:"Times New Roman"'><o:p> </o:p></span></p>
</div>
<![if !mso]><!-- doesn't matter -->
<![endif]></v:textbox>
</v:rect><![endif]--></span><!--[if mso & !supportInlineShapes & supportFields]><span
style='font-size:10.5pt;font-family:"Arial",sans-serif;mso-fareast-font-family:
"Times New Roman"'><v:shape id="_x0000_i1027" type="#_x0000_t75" style='width:315pt;
height:730.7pt'>
<v:imagedata croptop="-65520f" cropbottom="65520f"/>
</v:shape><span style='mso-element:field-end'></span></span><![endif]--><span
style='font-size:10.5pt;font-family:"Arial",sans-serif;mso-fareast-font-family:
"Times New Roman"'><o:p></o:p></span></p>
</td>
</tr>
</table>
</div>
</body>
</html>
Worth noting: the email displays as desired in the Email On Acid test suite for Outlook 2016 on Windows, but displays the broken behavior described here when viewed on the installation an Asus laptop (UX301 w/ i7-4558U CPU #2.8GHz & Iris Graphics 5100) running Windows 10 Home (version 1511 build 10586.36).
Outlook (no matter what version) converts all your pixels into points.
Then your emails will be broken on hight PDI laptops.
Here is described the problem and offered a solution.
I'm using two flex tables. One for header and one for data.
The one for data is wrapped with a scroll panel.
The size of my columns is presented with percentage and this is where my problem begins:
I set the width of both tables to 100%.
The thing is that the scrollbar isn't always visible. It's visible only when required.
So when the scrollbar is shown - there's a gap between the width of the header and the width of the data area inside the scrollpanel. (since the scrollbar itself has width of 16px)
This way, the titles of the columns, doesn't match precisely the data columns.
Any suggestions?
Thanks in advance!
Based on your comment from my other answer you are left with having to code. I have solved this sort of problem in the past by using a shim column. I wouldn't call it elegant but it did the trick. Basically, you have an extra column in your header at the end that acts as a shim for the scrollbar. When the scrollbar is being displayed then the shim column is displayed with the exact width of the scrollbar. When there is no scrollbar you hide the shim.
Setup your layout with the additional column. Style it however you want. I usually make it so it blends in with the adjoining column so the user doesn't see a little square when it is being displayed.
Add all your data rows to the content table as you normally would. Make sure the content table and all its tr/td are added to the DOM.
Once the data is added then test whether the scrollbar is visible. You can do this by checking if the scroll height is greater then the offset height.
ScrollPanel scrollPanel;
Element scrollElem = scrollPanel.getElement();
if (scrollElem.getScrollHeight() > scrollElem.getOffsetHeight()) {
// scrollbar is visible
}
If the scrollbar is displayed then show your shim column, otherwise hide it.
if (scrollElem.getScrollHeight() > scrollElem.getOffsetHeight()) {
// scrollbar is visible - show shim column
shimColumnTD.getStyle().setDisplay(Display.BLOCK);
}
else {
// scrollbar not visible - hide shim column
shimColumnTD.getStyle().setDisplay(Display.NONE);
}
Determine the width of the shim column so that it matches the width of the scrollbar. If you go look inside the below method you can see how it does this.
// calculate the width of the scrollbar for the given browser
int shimWidth = AbstractNativeScrollbar.getNativeScrollbarWidth();
Obviously, this is just all pseudo but it should lead you in the right direction. Good luck...
There are a lot of possible things you can do to keep columns in sync, but most of them requires active layout and/or preview resize events.
I guess that, for your use case, is much simpler and (performance wise) far faster to either:
shrink both tables a bit, to always accomodate the space for the scrollbar (or even remove the scrollbars at all, keeping the scrolling behavior functionality). Both solutions are generally achieved by using a pair of nested div, with the second one wider enough to hide/accomodate the scrollbar;
wrap your second table into a panel that does not shrink the content when it overflows. In GWT you can do that natively using a CustomScrollPanel (instead a ScrollPanel). Just pay attention that is a RequiresResize panel that needs either an interrupted chain of ProvidesResize containers, or an explict size.
Side note: If you ever need to calculate the size of the native scrollbars in a cross browser solution, just use AbstractNativeScrollbar.getNativeScrollbarHeight() (and/or the width one).
A common trick for this sort of thing that avoids complex code and layout is to simply fix the widths of all your columns except the last one. The last column will auto adjust and you won't have to worry about the scrollbar at all.
Here is a jsfiddle sample along with some sample html/css to show you what I mean. The caveat is that all of the columns have to have width (they cannot be percentages) except the last one.
jsfiddle example
CSS:
.container {
width: 500px;
border: 1px solid red;
}
.content-wrapper {
overflow: auto;
height: 75px;
}
table {
width: 100%;
border-collapse: collapse;
}
col {
width: 100px;
}
col:last-child {
width: auto;
}
.container td {
border: 1px solid green;
}
HTML:
<div class="container">
<div class="header-wrapper">
<table class="header">
<colgroup>
<col/>
<col/>
<col/>
<col/>
<col/>
</colgroup>
<tr>
<td>Column A</td>
<td>Column B</td>
<td>Column C</td>
<td>Column D</td>
<td>Column E</td>
</tr>
</table>
</div>
<div class="content-wrapper">
<table class="content">
<colgroup>
<col/>
<col/>
<col/>
<col/>
<col/>
</colgroup>
<tr>
<td>Row 1/A</td>
<td>Row 1/B</td>
<td>Row 1/C</td>
<td>Row 1/D</td>
<td>Row 1/E</td>
</tr>
<tr>
<td>Row 2/A</td>
<td>Row 2/B</td>
<td>Row 2/C</td>
<td>Row 2/D</td>
<td>Row 2/E</td>
</tr>
<tr>
<td>Row 3/A</td>
<td>Row 3/B</td>
<td>Row 3/C</td>
<td>Row 3/D</td>
<td>Row 3/E</td>
</tr>
<tr>
<td>Row 4/A</td>
<td>Row 4/B</td>
<td>Row 4/C</td>
<td>Row 4/D</td>
<td>Row 4/E</td>
</tr>
<tr>
<td>Row 5/A</td>
<td>Row 5/B</td>
<td>Row 5/C</td>
<td>Row 5/D</td>
<td>Row 5/E</td>
</tr>
</table>
</div
</div>
I am creating an email template to use in Pardot. I have coded the email up. It works fine in OSX Mail, Outlook 07 +, Opera Mail, however GMail is being a real pain. It is adding some weird height or something to the tr or td in my table.
Any suggestions?
<table border="0" cellpadding="0" cellspacing="0" width="228">
<tbody>
<tr valign="bottom">
<td valign="bottom"><span pardot-region=""><img src="widget_top.jpg" alt="Placeholder"></span></td>
</tr>
<tr bgcolor="#ffd13f">
<td style="padding: 10px;">
<h2><span pardot-region="">Subheading span across one or two lines for best practice:</span></h2>
<span pardot-region=""><p><b>Date:</b> Thursday 29 November</p>
<p><b>Time:</b> 1.30pm (GMT)</p>
<p><b>Where:</b> Register online ></p>
<p><b>Topic:</b> Dynamic performance management</p>
<p><b>Presenters:</b> Octavius Black, CEO and Sebastian Bailey, President</p></span>
</td>
</tr>
<tr valign="top">
<td valign="top"><span pardot-region=""><img src="widget_bottom.jpg" alt="Placeholder"></span></td>
</tr>
</tbody>
</table>
(this table is inside a set of tested tables).
Screen shot can be found here: http://i45.tinypic.com/15wzda9.png
Cheers :)
On the images you have to put (inline)
style="display:block;"
:)
display:block; is definitely needed. You probably should zero out everything in all img tags, and set width and heights also.
<img style="margin: 0; border: 0; padding: 0; display: block;" src="" width="600" height="150"
alt="">
Also, you don't need the spans inside the table cells. If you want to keep them, make sure they have margin and padding zero'd out there too.