#23 Device Pixel Ratio Image Tag Helper
Saturday, March 23, 2019
In this article we will create a new image tag helper that will take care of creating img tags that will respond to the device pixel ratio (DPR) of the users device. This allows us to serve a higher pixel density image for devices that can make use of it while saving a users data by sending down a smaller image for lower resolution devices. In this process of doing this we will create a base class that both of our tag helpers can inherit from which will allow us to keep our code as DRY as possible.
Parts
- Part 29: Offset Pager Urls
- Part 28: Offset Pager Start
- Part 27: Mock Context Builder
- Part 26: Mock Repository
- Part 25: Mock Async
- Part 24: Picture Tag Helper
- Part 23: Img DPR Tag Helper
- Part 22: Img Responsive Tag Helper
- Part 21: Img Optimized Display
- Part 20: Img Optimization
- Part 19: Img Lazy Loading
- Part 18: Img Responsive
- Part 17: Bottom Nav
- Part 16: Main Nav Cookie
- Part 15: Main Nav Mobile
- Part 14: Main Nav Search
- Part 13: Main Nav Auth
- Part 12: Main Nav Anchors
- Part 11: Main Nav Logo
- Part 10: Search Results
- Part 9: Search Manager
- Part 8: Search Start
- Part 7: Seeding the Database
- Part 6: Domain Database
- Part 5: Emailing Exceptions
- Part 4: Mailkit
- Part 3: View Renderer
- Part 2: Upgrade to 2.1
- Part 1: Quick Start
Base class
- WebUi
- Features
- Images
- ImageTagHelper.cs
- Images
- Features
In the previous article we created a tag helper that we can use to create device width responsive image tags and in this article we are creating a tag helper for dpr responsive image tags. The information that we need in order to create both tags we just have to format it just a bit differently for both. For this reason we are going to create a base class (a) that both of our tag helpers will inherit from.
ImageTagHelper.cs
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace WebUi.Features.Images
{
[HtmlTargetElement(Attributes = "alt,extension,src-fragment,sizes")]
public abstract class ImageTagHelper : TagHelper
{
[HtmlAttributeName("alt")] public string Alt { get; set; }
[HtmlAttributeName("extension")] public string Extension { get; set; }
[HtmlAttributeName("lazy-load")] public bool? LazyLoad { get; set; }
[HtmlAttributeName("src-fragment")] public string SrcFragment { get; set; }
[HtmlAttributeName("sizes")] public string Sizes { get; set; }
protected bool IsLazyLoaded => LazyLoad == null || LazyLoad.Value;
protected string[] SizeStrings { get; private set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "img";
output.TagMode = TagMode.StartTagOnly;
if (IsLazyLoaded)
{
output.AddClass("lazyload", HtmlEncoder.Default);
}
output.Attributes.Add("alt", Alt);
SizeStrings = Sizes.Split(',');
Process(output);
}
protected abstract void Process(TagHelperOutput output);
protected string ImageSrc(string size)
{
return $"{SrcFragment}-{size}w.{Extension}";
}
protected void SetSrcAndSrcset(TagHelperOutput output, string[] srcset)
{
string srcKey;
string srcsetKey;
if (IsLazyLoaded )
{
srcKey = "data-src";
srcsetKey = "data-srcset";
}
else
{
srcKey = "src";
srcsetKey = "srcset";
}
output.Attributes.Add(srcKey, ImageSrc(SizeStrings[0]));
output.Attributes.Add(srcsetKey, string.Join(',', srcset));
}
}
}
Update the responsive image tag helper
- WebUi
- Features
- Images
- ResponsiveImageTagHelper.cs
- Images
- Features
Now that we have a base class to use we need to update our responsive image tag helper to make use of it (b).
ResponsiveImageTagHelper.cs
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace WebUi.Features.Images
{
[HtmlTargetElement("responsive-image"]
public class ResponsiveImageTagHelper : ImageTagHelper
{
protected override void Process(TagHelperOutput output)
{
var srcset = new string[SizeStrings.Length];
var sizes = new string[SizeStrings.Length];
for (var i = 0; i < SizeStrings.Length; i++)
{
var size = SizeStrings[i];
srcset[i] = $"{ImageSrc(size)} {size}w";
sizes[i] = i < SizeStrings.Length - 1
? $"(max-width: {size}px) {size}px"
: $"{size}px";
}
output.Attributes.Add("sizes", string.Join(',', sizes));
SetSrcAndSrcset(output, srcset);
}
}
}
The dpr image tag helper
- WebUi
- Features
- Images
- DprImageTagHelper.cs
- Images
- Features
Next up is to finally create our dpr image tag helper (c). As I have mentioned previously it is basically the same as our previous tag helper we just need to change how we format the srcset attribute.
DprImageTagHelper.cs
using System.Linq;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace WebUi.Features.Images
{
[HtmlTargetElement("dpr-image")]
public class DprImageTagHelper : ImageTagHelper
{
protected override void Process(TagHelperOutput output)
{
var min = int.Parse(SizeStrings.First());
var srcset = new string[SizeStrings.Length];
for (var i = 0; i < SizeStrings.Length; i++)
{
var size = SizeStrings[i];
srcset[i] = $"{ImageSrc(size)} {int.Parse(size) / min:D}x";
}
SetSrcAndSrcset(output, srcset);
}
}
}
Examples
- WebUi
- Pages
- Image-Tag-Helper.cshtml
- Pages
Of course now that we have created the tag helper we need to make sure that it is behaving the way we want. To do this we will add an example for lazy loading disabled and for lazy loading enabled (d).
Image-Tag-Helper.cshtml
...
@if (Model.Problem == "resolution-switching")
{
...
else if (Model.Query == "same-size")
{
<div class="image-container">
<dpr-image src-fragment="/images/responsive-images/woman-balloon-chair-dark"
sizes="320,640"
extension="jpg"
alt="Woman sitting on a chair beside a balloon"
lazy-load="false"></dpr-image>
<div class="image-caption">
<p>Photo by Daria Shevtsova from Pexels</p>
<p>https://www.pexels.com/photo/woman-sitting-on-chair-beside-balloon-1391580/</p>
</div>
</div>
}
}
...
else if (Model.Problem == "lazy-loading")
{
...
else if (Model.Query == "same-size")
{
for(var i = 1; i <= 10; i++)
{
<div class="image-container same-size">
<dpr-image src-fragment="/images/responsive-images/woman-balloon-chair-dark-Copy@(i)"
sizes="320,640"
extension="jpg"
alt="Woman sitting on a chair beside a balloon"></dpr-image>
<div class="image-caption">
<p>Photo by Daria Shevtsova from Pexels</p>
<p>https://www.pexels.com/photo/woman-sitting-on-chair-beside-balloon-1391580/</p>
</div>
</div>
}
}
...
}