by WebSurfer
23. June 2023 13:52
先の記事「GridView に overflow 適用、三点リーダー表示」で、CSS の overflow: hidden と text-overflow: ellipsis を使って文字列の長さ制限するとともに三点リーダーを表示する例を紹介しましたが、文字列の中にエスケープされた文字、プロポーショナルフォント、サロゲートペア、絵文字などが含まれる場合どうなるかという話を書きます。
上の画像の下側の表の description 列の各行が、文字列の長さを 320px に制限するとともに末尾を三点リーダーで表示したものです。具体的にどのようにしたかと言うと、上側の表の description 列と同じ文字列を div 要素に入れて、その div 要素に以下の CSS を適用しました。ブラウザは Chrome、フォントはメイリオ、サイズは 16px です。
<style type="text/css">
div.style1
{
width: 320px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>
1 行目にある < > & という文字は、実際は < > & というエスケープされた文字列が、ブラウザ上では < > & と表示されたものです。
4 行目の絵文字 👨🌾 は、👨 と 🌾 を ZeroWidthJoinerで連結したもので、Unicode で言うと U+1F468 U+200D U+1F33E となっています。
文字はすべて ASP.NET により、コードビハインドでは UTF-16 のコードがそのまま UTF-8 に変換されてブラウザに送信されます。
(コードビハインドで扱われる UFT-16 で言うと、4 行目の絵文字 🍎 と 🍏 はサロゲートペアで、🍎 は 0xD83C 0xDF4E、🍏 は 0xD83C 0xDF4F です。👨🌾 は、👨 と 🌾 を ZeroWidthJoiner (0x200D) で連結したもの、つまり、0xD83D 0xDC68 0x200D 0xD83C 0xDF3E となっています。この記事とは直接関係ない話ですが、せっかく調べたので書いておきます)
上の結果から分かるように、各文字の長さやバイト数とは関係なく、ブラウザ上に表示された文字列の長さで制限がかかり、CSS の width: 320px で指定された幅いっぱいに三点リーダを含めて表示されています。
上の画像ではフォントはメイリオ、サイズは 16px ですが、MS Gothic などの等幅フォントを使った場合も、フォントサイズを変えた場合も、ブラウザ上に表示される文字列の長さで制限がかかるのは同じです。
三点リーダーを表示する text-overflow:ellipsis はもともと IE の独自拡張だそうですが、最近は他のブラウザでも取り入れられているようです。Windows 10 で Chrome 114.0.5735.134, Edge 114.0.1823.58, Firefox 114.0.2, Opera 100.0.4815.21 で試してみましたが、同じ結果が得られました。
参考に、上の画像を表示するのに使った ASP.NET Web Forms アプリのコードを載せておきます。
.aspx.cs
using System;
using System.Data;
namespace WebForms1
{
public partial class WebForm26 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// データソースとして DataTable を作成。
DataTable dt = new DataTable();
DataRow dr;
dt.Columns.Add(new DataColumn("id", typeof(Int32)));
dt.Columns.Add(
new DataColumn("description", typeof(string)));
dr = dt.NewRow();
dr["id"] = 1;
dr["description"] = "エスケープされた < > & " +
"などの文字はどのようになるか?";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["id"] = 2;
dr["description"] = "Proportional Font WWWWWWWWWWW " +
"iiiiiiii llllll などは?";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["id"] = 3;
dr["description"] = "サロゲートペア 𠀋 𡈽 𠮟 などは" +
"どのようになるか?";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["id"] = 4;
dr["description"] = "絵文字 🍎 🍏 (サロゲートペア) " +
"👨🌾 (ZWJ で結合) などは?";
dt.Rows.Add(dr);
// 上で作成した DataTable を GridView にバインド。
GridView1.DataSource = dt;
GridView1.DataBind();
GridView2.DataSource = dt;
GridView2.DataBind();
}
}
}
}
.aspx
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="WebForm26.aspx.cs" Inherits="WebForms1.WebForm26" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<style type="text/css">
body {
font-family: "メイリオ";
font-size: 16px;
}
div.style1 {
width: 320px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<p>制限しない場合 (フォント: メイリオ, 16px)</p>
<asp:GridView ID="GridView1"
runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="id" HeaderText="id" />
<asp:TemplateField HeaderText="description">
<ItemTemplate>
<asp:Literal ID="Literal1"
runat="server"
Text='<%# Eval("description") %>'>
</asp:Literal>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<p>overflow:hidden で制限 (フォント: メイリオ, 16px)</p>
<asp:GridView ID="GridView2"
runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="id" HeaderText="id" />
<asp:TemplateField HeaderText="description">
<ItemTemplate>
<div class="style1">
<asp:Literal ID="Literal1"
runat="server"
Text='<%# Eval("description") %>'>
</asp:Literal>
</div>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</form>
</body>
</html>