TML對話框已經停留了一段時間,但是直到最近,它還不是W3C推薦規范的一部分。既然主流瀏覽器已經開始支持對話元素,我們很可能會看到它被廣泛使用。本文簡要介紹了我們如何使用對話框,為什么需要新的元素以及如何使用它。
對話框是一種可用于多種方式的設計模式,包括但不限于:顯示重要信息,請求用戶選擇或擴展現有內容。雖然對話可以以不同的方式進行,但是最常用的是模態,與疊加層中的其他內容隔離。
直到新元素發布,要實現一個對話框到一個網站,你將不得不從頭開始編寫或使用外部庫 - 這種組件沒有標準的語法或默認樣式。缺乏標準意味著瀏覽器和屏幕閱讀器等輔助技術默認情況下無法區分對話框相關內容和其他頁面內容。
為了解決可訪問性問題,開發人員必須使用aria屬性(如role=“dialog”)來描述對話框中的內容。正確管理鍵盤焦點對于使用對話框的可訪問性也很重要,例如,對話框中必須至少有一個可調焦的控件。
一些偉大的庫被創建,使開發者更容易實現可訪問的對話框,比如Edenspiekermann的A11y Dialog。除了這樣的庫之外,像Bootstrap和Foundation這樣的CSS框架也使得它們內置的模式/對話框變得可用。
盡管今天這些庫和框架仍然是相關的和有用的,但是具有用于對話的本地HTML元素確保了這樣的經常使用的設計模式對于每個人都是很好的語法,標準和可訪問性。另外,在瀏覽器中內置對話邏輯可以節省那些寶貴的代碼字節!
現在我們明白為什么需要這個了,我們來看看我如何使用對話框元素。
對話框元素的標記就像在<dialog>標簽中包裝一些內容一樣簡單。為了使對話框起作用,我們需要一個按鈕來打開它,還有一個按鈕可以關閉或者撤銷它。
要使對話框默認打開,可以添加一個打開的屬性。
如果您的對話框包含一個表單,則表單元素的方法屬性應設置為對話框。
沒有JavaScript,對話元素將不會交互。我們可以將上面的HTML例子中的按鈕和對話框元素連接到一些點擊事件監聽器。
就是這樣,我們有一個可以正常運行本地化的對話框!
對話框元素的默認樣式不會適合每個人的口味......比較幸運的是,我們可以用CSS來設計樣式。
還有一個backdrop可以幫助我們選擇不同的背景
完整demo演示如下:
早在2014年,Chrome和Opera就開始支持對話元素,最近又推出了Chrome Android和三星瀏覽器。它也支持Firefox,但必須通過about:config啟用。盡管有幾個主要的瀏覽器不支持dialog,但有一個很好的polyfill可用。
窗這類組件已經十分常見,那么,這類組件應該怎么設計?這篇文章里,作者針對彈窗的設計方式做了詳細拆解,一起來看看,或許會對想了解C端界面組件的同學有所幫助。
彈窗是一種瞬態的交互式視圖,它會在“合適”的時間彈出到頁面的最頂層,并借由用戶的一次點擊完成關閉。
在我們習慣的語境中,彈窗僅指模態彈窗,故這里不討論那些看上去也是彈出式卻非模態彈窗,那些控件均有自己專門的分類,例如 Toast(吐司提示)。
這里需要專門解釋一下模態(Modal),模態是指一種會打斷用戶原本的任務流,并強制用戶完成當前交互的控件場景。
通常情況下會出現一層遮罩,將原頁面和需要交互的控件隔離開來,在用戶完成交互或點擊關閉該控件之前,無法在原來的頁面上繼續流程。例如典型的模態控件有:警告、抽屜、活動視圖、動作表單等等。
在過去的交互實踐中,模態是一種強制打斷用戶的場景,所以除非是優先級非常高的或緊急的情況,否則都會建議謹慎使用模態。不過這種謹慎的態度在如今的設計實踐中已經漸漸出現了一些變化。
彈窗有兩種主要的使用場景。
兩者是同一功能的控件,在 iOS 中稱為 Alert,也就是警告,在 Android 中被稱為 Dialog,也就是對話框。這是模態彈窗最傳統的用法,它通常是對系統層優先級最高的、最實時需要用戶做判斷或操作的事件進行的一種彈出式控件。在用戶完成該事件的處理之前,無法與別的控件進行交互。
在之后的行文中,我都會以警告來統稱警告和對話框。
這就是我之前說的,隨著新時代互聯網的深入發展,運營需求開始覆蓋并刷新系統各個控件原本的設計意圖,運營彈窗就此應運而生。但運營彈窗并非只能是廣告、抽獎、優惠券之類的活動內容,也可以是 App 內測邀請、升級提醒、請求開啟通知權限等偏功能的運營提示。
相對來說運營彈窗會比普通的警告承載更多的設計元素,會大幅度強化視覺的比重,但在交互上是跟警告沒有太多區別的——模態加簡單的交互依然是運營彈窗主要的交互特征。
在普遍的概念中模態彈窗好像都是出現在屏幕正中心,但其實不是這樣,模態彈窗還可以出現屏幕的底部,這么做的很少見,但的確有,例如抖音的青少年模式彈窗(這是彈窗,不是活動視圖,需要加以區分)。
在大多數情況下,警告彈窗都包含三部分主體,從上至下分別是:標題區、描述區和交互區。這三部分是警告彈窗的基本骨架,想要做更深一步的精細設計,也是在這三個部分的基礎之上。
1)標題的布局
在設計實踐中,標題的對齊可以居中或者居左。一般來說,在 iOS 中警告的標題默認居中,在 Android 中對話框的標題默認居左。
2)描述的布局
描述的布局大體上應與標題的布局保持一致,標題是如何對齊的,描述就如何對齊。
3)交互按鈕的布局
交互按鈕如果少于或等于兩個,那么優先使用水平排版,在此情況下還可以進一步選擇均分或者偏置,由于拇指的活動范圍有限,一般偏置在右側。
另一種垂直排版則適合任何數量的按鈕——盡管 iOS 規范要求交互按鈕的數量不超過三個,但實際情況卻依然需要具體問題具體分析,存在更多按鈕也是可能的。
4)交互按鈕的權重
通常我們還能看到 App 設計者會對不同的交互操作給予不同的傾向,這種傾向有時是功能需求,有時是運營需要,會讓傾向的按鈕更突出,會讓反傾向的按鈕更不易察覺(甚至置灰),會讓危險的按鈕呈現紅色。
5)額外內容
除了以上標準的三段式區域之外,警告彈窗內還可以加入其它一些額外的內容。描述區域可以依據情況增加額外的控件或設計元素,例如最常見的對話框,可以允許用戶輸入文本后再進行下一步操作;標題區域之上也可以增加一個圖標區,圖標可以更直觀提示該警告事件需求的操作、完成狀態或進程。
在警告彈窗的設計中,因為它的強功能性,這三段的文案要求要大于設計要求,盡管文案幾乎不歸我們設計師管,但是我在這里還是提一下這幾個部分的文案要求。
標題——盡可能簡練得總結當前所處的情況;如需額外操作,詢問用戶操作意見。
如果描述本身非常的長,那么就一定要加標題去凝練當前的事件,包括目前遇到的情況,以及可能的解決方案并詢問用戶的意見。
描述——盡可能用直接、人性化的口吻說出目前遇到的問題。
如果 App 是面向大眾用戶的,盡量避免用理工科思維寫出一些很繞且生澀的描述,尤其是如果中間還有程序語言那會更糟。這一點 windows 做的就非常不足,充滿了理工科的自說自話的氣息,也不管用戶到底看不看得懂。
按鈕——給出對結果的描述,避免要求語義邏輯判斷。
按鈕的文案最好是對結果的直接描述,按鈕上說的是什么,結果就會是什么,而不要讓用戶做語文題,否定之否定等于肯定這樣的情況避免出現——除非是故意的。例如“是否刪除XXXX”,正確的按鈕文案應當是“刪除”和“保留”,而非“是”和“否”。
盡管運營彈窗的布局可能眼花繚亂,但是它依然大致符合模態彈窗的三段式:標題、描述和交互按鈕。只不過運營彈窗的各個部分會輔以視覺元素表達。
此外,最重要的一點是,運營彈窗一定不能缺少「關閉」按鈕,雖然這個按鈕通常會浮在彈窗主體之外,是大是小全看想不想讓用戶輕易點到,但它不可或缺,否則用戶不知道如何退出這個彈窗。
隨著各類型 App 運營要求的逐漸提升,運營彈窗中視覺元素的運用也越發頻繁且有往愈加浮夸的方向發展的苗頭。可以在運營彈窗中使用的視覺元素大致有以下幾種:
1)圖標
最基礎的視覺元素,還是以常用的矩形為基底,但會輔以契合內容的圖標,其形式更加類似于警告。
2)插畫
現在最常見的花哨形式,插畫風格的多變性決定了它會在運營內容中大放異彩,甚至可以拋棄矩形邊界,完全以插畫內容為主體。
3)3D / 仿3D
隨著 3D 更多地進入 UI 領域,運營彈窗也逐漸開始使用 3D 元素,或者仿 3D 的元素。
4)圖片/視頻
圖片和視頻多用在品牌營銷的廣告中,不管是人還是物,都可以直接在彈窗中置入品牌的廣告物料圖或視頻。
這里收集了一些彈窗的案例,也可以作為設計時的參考:
作者:酸梅干超人;公眾號:超人的電話亭(ID:Superman_Call)
本文由 @超人的電話亭 原創發布于人人都是產品經理,未經許可,禁止轉載。
題圖來自Unsplash ,基于 CC0 協議
該文觀點僅代表作者本人,人人都是產品經理平臺僅提供信息存儲空間服務。
軟件開發中,很多地方需要用到與用戶消息提醒,用form繪制一個自己消息框。
首先在界面上繪制兩個按鈕,在之前文章有教程繪制一個button方法,也可以直接使用系統。
私有屬性
#region 私有屬性
private string message;
private MesBoxIcon mesIcon;
#endregion
公有屬性
#region 公有屬性
public MesBoxIcon MesIcon
{
get=> mesIcon;
set
{
mesIcon=value;
this.Invalidate();
if (value==MesBoxIcon.Info)
{
wenImageButton1.Visible=false;
}
}
}
public string Message
{
get=> message;
set
{
message=value;
Graphics g=this.CreateGraphics();
SizeF sizef=g.MeasureString(value, this.Font);
int width=(int) sizef.Width + this.FrameWidth * 2 + 80;
int height=this.TitleHeight + this.FrameWidth + panel1.Height;
this.Size=new Size(this.Width < width ? width : this.Width, this.Height < height ? height : this.Height);
this.Invalidate();
}
}
#endregion
MesBoxIcon 消息類型選擇
找到與自己需要繪制的圖檔
public enum MesBoxIcon
{
Asterisk,
Error,
Info,
Warning,
}
采用GDI繪制消息框
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle rec=new Rectangle(this.FrameWidth, this.TitleHeight, this.Width - this.FrameWidth * 2, this.Height - this.TitleHeight - this.FrameWidth - panel1.Height);
Rectangle recStr=new Rectangle(rec.X + 70, rec.Y, rec.Width - 70, rec.Height);
Rectangle recIco=new Rectangle(rec.X + 5, rec.Y + (rec.Height - 60) / 2, 60, 60);
Graphics g=e.Graphics;
g.DrawString(Message, Font, new SolidBrush(this.ForeColor), recStr, WenSkin.Controls.ControlHelper.StringConters);
switch (MesIcon)
{
case MesBoxIcon.Asterisk:
g.DrawImage(Properties.Resources.Asterisk, recIco);
break;
case MesBoxIcon.Error:
g.DrawImage(Properties.Resources.error, recIco);
break;
case MesBoxIcon.Info:
g.DrawImage(Properties.Resources.Info, recIco);
break;
case MesBoxIcon.Warning:
g.DrawImage(Properties.Resources.Warning, recIco);
break;
default:
break;
}
}
兩個按鈕點擊事件
private void wenImageButton2_Click(object sender, EventArgs e)
{
this.DialogResult=DialogResult.OK;
}
private void wenImageButton1_Click(object sender, EventArgs e)
{
this.DialogResult=DialogResult.Cancel;
}
可以根據自己需求更改。
多個構造函數示例
public MesBox()
{
InitializeComponent();
this.SizeChanged +=(s, e)=>
{
if (wenImageButton1 !=null)
wenImageButton1.Width=(this.Width - this.FrameWidth * 2) / 2;
};
Text="消息";
mesIcon=MesBoxIcon.Info;
this.StartPosition=FormStartPosition.CenterScreen;
}
public MesBox(string text) : this()
{
Message=text;
}
public MesBox(string text,MesBoxIcon mesBoxIcon) : this(text)
{
MesIcon=mesBoxIcon;
switch (MesIcon)
{
case MesBoxIcon.Asterisk:
Text="提醒";
break;
case MesBoxIcon.Error:
Text="錯誤";
break;
case MesBoxIcon.Info:
Text="消息";
break;
case MesBoxIcon.Warning:
Text="警告";
break;
default:
break;
}
}
public MesBox(string text,string caption, MesBoxIcon mesBoxIcon) : this(text)
{
Text=caption;
}
至此,一個自主彈窗繪制完成
接下來調用
var m=new MesBox(text, MesBox.MesBoxIcon.Asterisk).ShowDialog();
if (m==DialogResult.OK)
true;
else
false;
一行代碼即可,是不是很方便。
關注文林軟控,帶你一起C# 美化.NET 控件。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。