How to create Responsive Email Template? - responsive-design

How to create Responsive Email Template?
I can build responsive layout using media-query but these styles we can write only in external/internal CSS. Email template we cannot use DIV and external/internal CSS.
How can i build responsive email template.
Thanks,
Shanid

Using media queries in an HTML email is not a very good solution to developing a responsive HTML email because the vast majority of your audience is not going to see it the way you intend.
Gmail will not preserve any CSS in the head of an html email. This is where media queries are, so .. won't work.
Android supports media queries but it's buggy at best.
The best way to develop a pseudo-responsive HTML email is to build a fluid layout HTML email. Design your email with (for simplicity) a single column layout. You can develop a fluid layout with a multi-column layout but it can get pretty complicated quick.
Design your layout as normal, inline all your styling and using depreciated HTML attributes rather than css styling.. doesn't matter if it's inline, CSS still won't play well in HTML emails. Use it sparingly, don't use it at all if you can avoid it.
Do not assign height to your elements and assign width only in percentage values. Therefore allowing the device displaying the email to determine the best width to display based on the percentage values rather than specific pixel sizes.
<table width="90%" cellpadding="0" cellspacing="0" border="0">...</table>
Here's a good example of a fluid layout: http://woothemes.createsend1.com/t/ViewEmail/y/1D01C6AE9D028347

You need to understand that responsive emails, while possible, can't work on every mail client. As an example, Gmail strips all your head tag from the email, so no media queries are allowed, therefore no responsiveness. From what I've tested, responsive emails can be displayed in Outlook, Apple Mail, and a few others with standard media queries. For those, you'd have to use the typical breakpoints and apply them to trs or tds. Now, that can be tricky. You have to make sure it won't break your table layout so you really need to plan in advance what will change in your layout.
If you want it to work mostly on everything, I'd suggest you use fluid layouts using % widths. But if you really want some web responsiveness, it's the same as any responsive website. Just be aware that it will not work everywhere. Like this:
#media (max-width:680px) {
.hide { display:none; }
.main { width:440px }
.header { width:440px; }
.header-img { width:440px }
.footer { width:440px; }
.footer-size { width:440px; }
}
#media (max-width:440px) {
.hide { display:none; }
.main { width:100% }
.header { width:100%; }
.header-img { width:100%; height:auto; }
.logo-img { width:75px; height:30px; }
.icon-img { width:19px; height:18px; }
.icon-wrap { width:19px; }
.footer { display:none !important; }
.footer-size { width:100% }
}
#media (max-width:240px) {
.hide { display:none; }
.main { width:100% }
.header { width:100%; }
.header-img { width:100%; height:auto; }
.logo-img { width:75px; height:30px; }
.icon-img { width:19px; height:18px; }
.icon-wrap { width:19px; }
.button { width:100%; height:auto; }
.footer { display:none !important; }
.footer-size { width:100% }
}
(That's just some code from an email campaign I worked on, btw)

You can use media queries for common mailclients. Webclients rely heavily on inline css. Work with as much percentages as possible on your tables (100%) and max widths for tables that may not scale bigger than a certain amount of pixels.
Nested tables within a 100% wrapper table always stack inherited.

U should learn #media queries first. Is't something for write here because of many info.

Related

Can I store a ref in Redux store, or is it considered bad practice?

The context:
Short explanation why I'm even asking this. I have a React App with Redux.
I have a component that shows a List of Chat Rooms. I also have a Appbar from Material UI with a position of sticky. Also the list of chatRooms is sticky so it sticks to the left side, without scrolling with the list of chats in the middle.
This won't work ofc because the list of chatRooms will hide behind the AppBar or better said, overlap with it. So I need to set the top value for chatRooms according to the AppBar's height.
The question:
My idea was to add useDimensions hook and measure the height of the AppBar. I need to pass a ref to the appbar. And then set the top value of chatRooms equal to this height. But I can't pass this directly to the component. So my question is:
Can I store the ref in redux store, or is it considered bad practice? If so how to solve this problem?
Don't store a ref in your redux store, there are better ways to fix this problem. I have a layout similar than yours and it works with css only. You should avoid sticky because of this overlap problem and use a css grid instead.
Here is my css, as you can see there are no sticky, but just a full page grid:
/* Main grid container (2 columns, 2 rows) */
#root {
height: 100%;
display: grid;
grid-template-columns: 220px 1fr;
grid-template-rows: 56px 1fr;
}
/* Top App bar, height=56px */
header {
grid-column: span 2;
}
/* List of chatRooms, width=220px */
aside {
overflow-x: hidden;
overflow-y: auto;
}
/* List of chats */
main {
overflow-y: auto;
}
If you want this grid to fill the whole page, then you need to add:
html { height: 100% }
body { height: 100% }

Fotorama: captions only in fullscreen

I would like to know if there is a possibility to show the caption only in fullscreen mode.
I need this for a custom website I an working on and the client requested that the captions only be shown in fulscreen mode.
Use this css rules
.fotorama .fotorama__caption {
display: none;
}
.fotorama--fullscreen .fotorama__caption {
display: block;
}

Change font size of chart (n3-charts/line-chart)

I am using https://github.com/n3-charts/line-chart library to generate charts. Is it possible to change font size of axis labels? I could not find such option in official documentation.
Something like this on the CSS would work
.tick text {
font-size: 120%;
}
Edit: The appearance of many SVG elements can be configured using CSS, just inspect them in the browser and try modifying them.
When the chart is generated it has it's own classes that you can take advantage of overwriting... Here are all the axis for example:
// X-Axis Font
.x-axis {
font-size: 120%;
}
// Left Y-Axis
.y-axis {
font-size: 130%;
}
// Right Y-Axis
.y2-axis {
font-size: 140%;
}
Hope that helps.

How to properly translate shadow DOM CSS selectors to non-shadow-DOM selectors

I want to test Polymer applications with non-Shadow-DOM capable browsers like Firefox, PhantomJS, and maybe others using WebDriver.
WebDriver commands for Firefox and PhantomJS fail when I use something like
driver.findElement(const By.cssSelector('* /deep/ #some-div'));
Are there some rules how to best translated/approximate these selectors when the polyfills can not be applied:
/deep/
::shadow
:host()
:host-context()
:content
I would like to create a function that translates such selectors automatically to non-shadow-DOM selectors for browsers that don't support them before sending the request and for that I need to know how to translate them.
Question is a bit old, but in case you haven't figured it out yourselves yet.
/deep/ (deprecated): As you said in your answer, just removing it should work in most of the cases.
::shadow (deprecated): Can also just be removed. Replacing it with > might not work if node which you are targeting is not an immediate child of host element's shadow root.
:host() pseudo classes is used to select custom element from inside shadow-dom, in non-supported browsers it will be equal to selecting parent from child element. Since we don't have parent selectors in css and you are writing js for conversion, you can identify tagName of host element and use it instead of :host selector. Something like below:
:host {
opacity: 0.4;
transition: opacity 420ms ease-in-out;
}
:host(:hover) {
opacity: 1;
}
:host(:active) {
position: relative;
top: 3px;
left: 3px;
}
/*Convert it to*/
x-element {
opacity: 0.4;
transition: opacity 420ms ease-in-out;
}
x-element:hover {
opacity: 1;
}
x-element:active {
position: relative;
top: 3px;
left: 3px;
}
:host-context(<selector>) pseudo class matches the host element if it or any of its ancestors matches <selector>. for example:
Below rule will apply on custom element only when it's a descendant of an element with the class .different.
:host-context(.different) {
color: red;
}
<body class="different">
<x-foo></x-foo>
</body>
It won't be very easy to replace this one with anything simple. Even webcomponents polyfill doesn't attempt it. I can't think of any css only way to achieve this.
::content targets distributed child nodes of host element, i.e. all elements which are picked to display using content selectors. Replacing ::content selectors with tagName of host elements should work here. i.e.
::content > h3 {
color: green;
}
/*replace it with*/
x-element h3 {
color: green;
}
Note that I have removed child selector > also from above, because in non-supported browsers after distribution h3 won't be a direct descendant of x-element anymore. Given the way content selector is used, I'd suggest removing child selector also wherever available.
/deep/ can just be removed
::shadow can be replaced by >
don't know about the others yet

Can I use the !important css keyword with Angularjs ng-style directive?

I'm having an issue with boostrap3 and it's default background: transparent !important; print setting.
I have the need to show a heatmap in my webapp and have these printable.
I'm using an ng-style directive for that to dynamically calculate the needed background-color.
In short, this is the html part
<div class="heatmap" ng-style="scalecolor(10)">lorem ipsum</div>
and this is the controller part
$scope.scalecolor = function(perc) {
return { backgroundColor: plnkUtils.scaleColorInt('#EE0000', '#88FF00', perc) }
};
However, because bootstrap3 sets all backgrounds to transparent with the !important keyword, I can't print these.
This is the part of bootstrap 3.1.0 css causing the issue with missing background-color:
#media print {
* {
color: #000 !important;
text-shadow: none !important;
background: transparent !important;
box-shadow: none !important;
}
}
Since the inverse of background: transparent !important; is background: color hex code !important;
(see here )
I'm trying to set that using the ng-style, but then the exclamantion mark causes Angularjs to flip when I try this:
$scope.scalecolor = function(perc) {
return { backgroundColor: plnkUtils.scaleColorInt('#EE0000', '#88FF00', perc) !important }
};
or alternatively when I try this in the html template
ng-style="scalecolor(10) !important"
Anyone out there that knows how I can use the !important css keyword with the Angularjs ng-style directive to override the bootstrap3 wildcard?
For those who want to see this with their own eyes, here's a plunker showing the issue
Apparently you can't and it's a known issue but there is some workaround that can be found here:
https://github.com/angular/angular.js/issues/5379
The solution below has been copied from the site just in case the link breaks, or get changed.
You're not able to use the !important directive in the DOM style property in either Chrome nor FF (probably others too). The style attribute gets parsed as CSS, but the HTMLElement.style property doesn't. Unfortunately you're not able to set a property's priority here (in Gecko/Blink/Webkit, at least).
So, there are some workarounds here:
Workaround #1
<ANY data-ng-attr-style="{{ blue && 'background-color: blue!important' || '' }}">
</ANY>
This would be your best way to go in terms of browser-support, because the CSS property priority will get parsed correctly here.
Workaround #2
Alternatively, you can also do the following in javascript:
$scope.$watch(conditionalStyle);
function conditionalStyle() {
if ($scope.blue) {
$element[0].style.setProprety('background-color', 'blue', 'important');
} else {
$element[0].style.backgroundColor = '';
}
}
Where $element is a jQuery/jqLite object referencing an HTMLElement.
Note: caveats are not supported in IE < 9 so workaround #1 is probably your best bet for this behavior where you depend on property priority...
Using the tips for #Wawy I updated my code to get it to work.
For anyone landing on this page, for clarification I made an updated Plunker that can be found here
In short, this is now the html part
<div class="heatmap" ng-attr-style="{{ngAttrScaleColor(10)}}">YES, ng-attr-style works !</div>
and this is the controller part
$scope.ngAttrScaleColor = function(perc) {
return 'background-color: ' + plnkUtils.scaleColorInt('#EE0000', '#88FF00', perc) + '!important';
};

Resources