Fast Blazor ์ ์‘๊ธฐ - slog

Microsoft Fast์˜ Blazor ์ปดํฌ๋„ŒํŠธ์ธ Fast Blazor์— ์ ์‘ํ•˜๊ณ  ์—…๋ฌด์— ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋‹จ๊ธฐ ์Šฌ๋กœ๊ทธ ์ž…๋‹ˆ๋‹ค.

8๊ฐœ์˜ ์ข‹์•„์š”

๊ฐœ์ธ์ ์œผ๋กœ ๊ฐ€์žฅ ๋งˆ์Œ์— ๋“œ๋Š” Blazor UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ธ MudBlazor์™€ ์–ด๋– ํ•œ ์ฐจ์ด๊ฐ€ ์žˆ๋Š”์ง€ ์–ด๋–ค ์žฅ/๋‹จ์ ์ด ์žˆ๋Š”์ง€๋„ ๊ฐ™์ด ๋น„๊ตํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

4๊ฐœ์˜ ์ข‹์•„์š”

์˜คโ€ฆ ์ €๋„ toy project๋ฅผ MudBlazor๋กœ ํ”ฝํ–ˆ๋Š”๋ฐใ…Žใ…Žโ€ฆ awesomeblazor์—์„œ ๋’ค์ง„ ๊ฒฐ๊ณผ ์ œ์ผ ๋‚ซ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๋‹ค๋ฅธ component๋“ค์€ ์จ๋ณด์ง€ ์•Š์•„์„œ ๋น„๊ตํ•ด์ฃผ์‹œ๋ฉด ๋„์›€์ด ๋งŽ์ด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค!

4๊ฐœ์˜ ์ข‹์•„์š”

Fast Blazor๋Š” ๋‹ค์Œ์˜ ๋ช…๋ น์œผ๋กœ ํ”„๋กœ์ ํŠธ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

| ํ”„๋กœ์ ํŠธ ํ…œํ”Œ๋ฆฟ ์„ค์น˜

dotnet new install Microsoft.Fast.Templates.FluentUI::2.0.3

์ดํ›„ ์ƒˆ ํ”„๋กœ์ ํŠธ์— ๊ด€๋ จ ํ”„๋กœ์ ํŠธ ํ…œํ”Œ๋ฆฟ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

image

image

3๊ฐœ์˜ ์ข‹์•„์š”

๋””์ž์ธ ํ† ํฐ

FAST๋Š” ์ ์‘ํ˜• UI(Adaptive UI)๋ผ๋Š” ์‹œ์Šคํ…œ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด์— ๋”ฐ๋ผ ์ฆ‰๊ฐ์ ์ธ ํ…Œ๋งˆ ์ ์šฉ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

https://www.fast.design/ ์˜ Dynamic themes with Adaptive UI๋ฅผ ์‚ดํŽด์ฃผ์„ธ์š”.
image

์ด๋Š” "๋””์ž์ธ ํ† ํฐ"์„ ํ†ตํ•ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. Fast Balzor์—์„œ๋Š” ๊ฐ ํ† ํฐ์ด ์„œ๋น„์Šค์— ๋“ฑ๋ก๋˜์–ด ์žˆ์–ด์„œ [Inject] ํŠน์„ฑ์„ ์ด์šฉํ•ด ๊ฐ€์ ธ๋‹ค ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

image

๋‹ค์Œ์ฒ˜๋Ÿผ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์ง์ ‘ ์‚ฌ์šฉํ•  ์ˆ˜ ๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

image

image

<FluentDesignSystemProvider>๋ฅผ ์ด์šฉํ•ด app.razor์— ์ผ๊ด„ ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

image

4๊ฐœ์˜ ์ข‹์•„์š”

Fast Blazor์˜ ๋ฐ๋ชจ๋Š” ์•„๋ž˜์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://aka.ms/fluentui-blazor

4๊ฐœ์˜ ์ข‹์•„์š”

Fast ๋ฐ Fast Blazor ๋Š” ๋ณ„๋„์˜ ๋ ˆ์ด์•„์›ƒ ์‹œ์Šคํ…œ์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ € ๊ฐ™์ด css๊ฐ€ ์•ฝํ•œ ๊ฐœ๋ฐœ์ž์˜ ์ž…์žฅ์—์„œ๋Š” ์•„์‰ฌ์šด ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

์ด์— ๋ฐ˜ํ•ด MudBlazor๋Š” css๋ฅผ ์•ˆ์จ๋„ ํ™”๋ฉด ๊ตฌ์„ฑ์ด ๊ฐ€๋Šฅํ•  ์ •๋„๋กœ ๋‹ค์–‘ํ•œ ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

5๊ฐœ์˜ ์ข‹์•„์š”

Blazor์—์„œ ์ž˜ ์ค€๋น„๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ˆ˜์ค€์—์„œ๋Š” Fast Blazor๋‚˜ MudBlazor๋‚˜ ํŠน๋ณ„ํ•œ ๋‚œ์ด๋„์˜ ์ฐจ์ด๋Š” ์—†์–ด ๋ณด์ž…๋‹ˆ๋‹ค. (๊ทธ ์ปดํฌ๋„ŒํŠธ์˜ ์‚ฌ์šฉ๋ฒ•์— ์–ผ๋งˆ๋‚˜ ๋นจ๋ฆฌ ์ต์ˆ™ํ•ด์ง€๋ƒ ์ •๋„์˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค.)

๋‹ค๋งŒ Fast Blazor๋Š” Fast์˜ ๋ž˜ํ•‘์ด๊ณ  Fast๋Š” ํ˜„๋Œ€์ ์ธ ๋ฐฉ์‹์œผ๋กœ ์›น ๊ตฌ์„ฑ ์š”์†Œ ๋‹จ์œ„๋กœ ํ›Œ๋ฅญํ•˜๊ฒŒ ๋””์ž์ธ ๋ฐ ํ™•์žฅ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ์ ์ด ์žฅ์ ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. (ํ™•์‹ ํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋Š” ์•„์ง Fast๋ฅผ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ)

ํŠน์ • ๊ธฐ์ˆ ์„ ๋น ๋ฅด๊ฒŒ ์ตํžˆ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์น˜ํŠธ ์‹œํŠธ(์ปจ๋‹ ํŽ˜์ดํผ)๋งŒํผ ์ข‹์€ ๊ฒƒ์ด ์—†์Šต๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ข‹์•„์š”

Fast์˜ ๊ฐ•์ ์€ ํ…Œ๋งˆ๋ฅผ ์–ด๋–ป๊ฒŒ ๋™์ ์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Fast Blazor์˜ ์ƒ˜ํ”Œ ์ฝ”๋“œ ์ค‘ ํ…Œ๋งˆ ์Šค์œ„์น˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด

    public async void SwitchTheme()
    {
        await Task.Delay(50);

        if (_inDarkMode)
            baseLayerLuminance = StandardLuminance.DarkMode;
        else
            baseLayerLuminance = StandardLuminance.LightMode;

        await BaseLayerLuminance.SetValueFor(container, baseLayerLuminance.GetLuminanceValue());

        GlobalState.SetLuminance(baseLayerLuminance);

        await _jsModule!.InvokeVoidAsync("switchHighlightStyle", baseLayerLuminance == StandardLuminance.DarkMode);
    }

์ด๋Ÿฐ ์ฝ”๋“œ๋กœ ๋™์ž‘ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ ํ•œ์ค„์ธ๋ฐ์š”,

await BaseLayerLuminance.SetValueFor(container, baseLayerLuminance.GetLuminanceValue());

๋””์ž์ธ ํ† ํฐ ์ค‘ BaseLayerLuminance ๊ฐ’์„ ๋ณ€๊ฒฝํ•จ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Fast์—์„œ๋Š” ๋‹คํฌ๋ชจ๋“œ์™€ ๋ผ์ดํŠธ ๋ชจ๋“œ๋ฅผ Luminance(ํœ˜๋„)๋กœ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋“ฏ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, Dark|Light ๊ฐ€ ์•„๋‹ˆ๋ผ 0.2f, 0.8f ๋“ฑ์˜ ํŠน์ • ๊ฐ’์œผ๋กœ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ ์šฉ์€ ์ฆ‰๊ฐ์ ์œผ๋กœ ๋น ๋ฅด๊ฒŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

image

image

3๊ฐœ์˜ ์ข‹์•„์š”

Fast Blazor๋ฅผ ํ˜„์—…์— ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋‚จ์€ ์ €์˜ ์ˆ™์ œ๋Š” ๋ ˆ์ด์•„์›ƒ ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ทธ๋ƒฅ Bootstrap์˜ ๋ ˆ์ด์•„์›ƒ ์‹œ์Šคํ…œ์„ ๊ทธ๋Œ€๋กœ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค ๋งŒโ€ฆ Blazor์—์„œ ์ปดํฌ๋„ŒํŠธ ํ˜•ํƒœ๋กœ ๋ ˆ์ด์•„์›ƒ์„ ์‚ฌ์šฉํ•  ๋ฐฉ๋ฒ•์„ ์ข€ ๋” ๋ฆฌ์„œ์น˜ ํ•ด๋ด์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค.

์‚ดํŽด๋ณผ ๋งŒํ•œ ์˜ˆ๋กœ, Fast Blazor์˜ ๋ฐ๋ชจ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด Stack์ด๋ผ๋Š” ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ๋Š”๋ฐ ๊ตฌํ˜„์„ ์‚ดํŽด๋ณด๋ฉด ๊ฐ„๊ฒฐํ•˜๊ณ  ์žฌ๋ฐŒ์Šต๋‹ˆ๋‹ค. (Stack์€ ์šฐ๋ฆฌ๊ฐ€ ์•Œ๊ณ  ์žˆ๋Š” StackPanel์˜ ๊ทธ๊ฒƒ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค)

| stack.razor

@* Remember to replace the namespace below with your own project's namespace. *@
@namespace FluentUI.Demo.Shared

@inherits FluentComponentBase

<div class="@ClassValue" style="@StyleValue" @attributes="AdditionalAttributes">
    @ChildContent
</div>

HTML ์ž…์žฅ์—์„œ๋Š” ๋ ˆ์ด์•„์›ƒ ๋ธ”๋ก์€ ๋‹จ์ง€ div ๋ธ”๋ก์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

| Stack.razor.cs

...

    protected string? ClassValue => new CssBuilder(Class)
        .AddClass("stack-horizontal", () => Orientation == Orientation.Horizontal)
        .AddClass("stack-vertical", () => Orientation == Orientation.Vertical)
        .Build();

    protected string? StyleValue => new StyleBuilder()
        .AddStyle("align-items", GetHorizontalAlignment(), () => Orientation == Orientation.Vertical)
        .AddStyle("justify-content", GetVerticalAlignment(), () => Orientation == Orientation.Vertical)

        .AddStyle("justify-content", GetHorizontalAlignment(), () => Orientation == Orientation.Horizontal)
        .AddStyle("align-items", GetVerticalAlignment(), () => Orientation == Orientation.Horizontal)

        .AddStyle("column-gap", $"{HorizontalGap}px", () => HorizontalGap.HasValue)
        .AddStyle("row-gap", $"{VerticalGap}px", () => VerticalGap.HasValue)
        .AddStyle("width", Width, () => !string.IsNullOrEmpty(Width))
        .AddStyle("flex-wrap", "wrap", () => Wrap)

        .AddStyle(Style)
        .Build();
...

์†์„ฑ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ Class์™€ ์ ์ ˆํ•œ Style์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Fast Blazor์—์„œ Lab ํ˜•ํƒœ๋กœ (NuGet ํŒจํ‚ค์ง€์—๋Š” ํฌํ•จ๋˜์ง€ ์•Š์Œ) ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ๋ฅผ Header, Footer, BodyContent, Layout, MainLayout, Spacer, Stack์œผ๋กœ ์ œ๊ณตํ•˜์ง€๋งŒ MudBlazor์˜ ๊ทธ๊ฒƒ์— ๋น„ํ•ด์„œ๋Š” ๋งŽ์ด ๋นˆ์•ฝํ•ฉ๋‹ˆ๋‹ค. (์ด๊ฒƒ์€ Fast์˜ ๋ฌธ์ œ๋ผ๊ธฐ ๋ณด๋‹ค๋Š” ์ €์˜ css ํ™œ์šฉ์˜ ์ œํ•œ์— ๋”ฐ๋ฅธ ๋‹จ์ ์œผ๋กœ ๋น„์ถฐ์ง€๋Š” ์ ์ž…๋‹ˆ๋‹ค.)

4๊ฐœ์˜ ์ข‹์•„์š”

Fast ํŠน์ง• ์ •๋ฆฌ

Fast๋Š” ์ด๋ฏธ ์ž˜ ๋””์ž์ธ๋œ Fast ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉ์ž ์ง€์ • HTML ์š”์†Œ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ์ด ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค. ์ด๋Š” ์ƒˆ HTML ํƒœ๊ทธ๋ฅผ ์ •์˜ํ•˜๊ณ , ํ‘œ์ค€ ๊ตฌ์„ฑ ์š”์†Œ ์ˆ˜๋ช… ์ฃผ๊ธฐ์— ์—ฐ๊ฒฐํ•˜๊ณ , HTML ๋ Œ๋”๋ง ๋ฐ CSS๋ฅผ ์บก์Šˆํ™”ํ•˜๊ณ , CSS๋ฅผ ๋งค๊ฐœ ๋ณ€์ˆ˜ํ™” ํ•˜๊ณ , ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์Šคํ‚จํ•˜๋Š” ๋“ฑ์˜ ๊ธฐ๋Šฅ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์€ ํ‘œ์ค€ํ™”๋ฅผ ํ†ตํ•ด ๊ฑฐ์˜ ๋ชจ๋“  ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ •์ƒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๋‹ค์–‘ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์ž˜ ๊ฒฐํ•ฉ๋˜๋ฉฐ Fast ํ™ˆํŽ˜์ด์ง€์—์„œ ์†Œ๊ฐœํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ - Angular, ASP.NET, Aurelia, Blazor, Ember, React, Rollup, Svelte, Vite, Vue, Webpack๋“ฑ๊ณผ ์ž˜ ๊ฒฐํ•ฉ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ Fast๋Š” ๋‹ค์Œ์˜ ๊ธฐ์ˆ  ์Šคํƒ์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š”๋ฐ

image

์ด ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒˆ๋กญ๊ฒŒ ๊ตฌํ˜„ํ•  ํ•„์š” ์—†์ด ๊ธฐ ๊ตฌํ˜„๋œ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ ๋‹จ์œ„ (์ƒํƒœ ๊ด€๋ฆฌ, ์ ‘๊ทผ์„ฑ, ํ‚ค๋ณด๋“œ ํƒ์ƒ‰ ๋ฐ ํ™•์žฅ์„ฑ/์ปดํฌ์ง€์…˜ ๋ชจ๋ธ ๋“ฑ)์™€ ๋™์  ์Šคํƒ€์ผ ๋™์ž‘, CSS ์†์„ฑ ๊ด€๋ฆฌ, ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ƒ‰์ƒ, RTL, ๊ณ ๋Œ€๋น„ ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

@microsoft/fast-foundation๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ Google์˜ ๋จธํ‹ฐ๋ฆฌ์–ผ ๋””์ž์ธ์ด๋‚˜ ํŠธ์œ„ํ„ฐ์˜ ๋ถ€ํŠธ ์ŠคํŠธ๋žฉ๊ณผ ๊ฐ™์€ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Fast Blazor ํŠน์ง• ์ •๋ฆฌ

Fast Blazor๋Š” Fast์˜ Balzor ๋ž˜ํ•‘์ž…๋‹ˆ๋‹ค. Fast์˜ ์‚ฌ์šฉ์ž ์ง€์ • HTML์€ Blazor์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ž˜ํ•‘๋ฉ๋‹ˆ๋‹ค.

๋””์ž์ธ ํ† ํฐ์„ ์ œ์™ธํ•œ Fast์˜ ๊ธฐ๋Šฅ์ด Fast Blazor์— ๋…ธ์ถœ๋˜๋Š”์ง€๋Š” ํŒŒ์•…๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (๋ฐ๋ชจ์—๋Š” ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.) Fast๋ฅผ ์ด์šฉํ•ด์„œ ๋งŒ๋“ค์–ด์ง„ FluentUI ์ปดํฌ๋„ŒํŠธ๋ฅผ Blazor์—์„œ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก Blazor ์ปดํฌ๋„ŒํŠธ๋กœ ๋ž˜ํ•‘ํ•œ ์ •๋„๋กœ ์ดํ•ด๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

Blazor์—์„œ ์ข€ ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก Lab ์ˆ˜์ค€์œผ๋กœ ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ ค ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ ˆ์ด์•„์›ƒ ์‹œ์Šคํ…œ ๋ฟฅ๋งŒ ์•„๋‹ˆ๋ผ NavMenu๋ผ๋˜๊ฐ€ ๋ฑƒ์ง€, Highligther ๋“ฑ์ž…๋‹ˆ๋‹ค.

5๊ฐœ์˜ ์ข‹์•„์š”

๊ฒ€์ƒ‰ํ•ด ๋ณธ ๊ฒฐ๊ณผ WPF์˜ Grid, StackPanel ๊ฐ™์€ Blazor์šฉ ๋ ˆ์ด์•„์›ƒ ์ „์šฉ ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋‚˜ํƒ€๋‚˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์–ด์ฐŒ๋ณด๋ฉด CSS๊ฐ€ ์ด๋ฏธ ๊ทธ ๊ฒƒ์„ ํ›Œ๋ฅญํ•˜๊ฒŒ ํ•ด๊ฒฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ด ์•„๋‹๊นŒ ์ƒ๊ฐํ•˜๋Š”๋ฐ์š”, ์ฐธ๊ณ ๊ฐ€ ๋˜๋Š” ์•„๋ž˜์˜ ๊ธ€์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค.

4๊ฐœ์˜ ์ข‹์•„์š”

CSS ๊ฒฉ๋ฆฌ ์˜ค๋™์ž‘

์™ ์ผ์ธ์ง€ CSS ๊ฒฉ๋ฆฌ๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ ๋‹ค์Œ ์ฒ˜๋Ÿผ CSS ๊ฒฉ๋ฆฌ๋ฅผ ์„ค์ •ํ–ˆ๋Š”๋ฐ

| _Laout.cshtml

...
<link href="BlazorApp33.styles.css" rel="stylesheet" />
...

| Components.razor.css

fluent-card {
    --card-height: 400px;
    --card-width: 500px;
    padding: 20px;
    margin: 12px;
}

.class-override {
    height: 163px;
    width: 300px;
}

.state-override {
    --card-width: 350px;
    --card-height: 300px;
}

.contents {
    display: flex;
    flex-direction: column;
}

์‹คํ–‰ํ•˜๋ฉด ๋‹ค์Œ ์ฒ˜๋Ÿผ ์Šคํƒ€์ผ์ด ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ถ„์„ํ•ด๋ณด๋ฉด ๋ณ€ํ™˜๋œ html ์ฝ”๋“œ๋ฅผ ๋ณด์•˜์„ ๋•Œ,

<fluent-card neutral-palette-source="#CABA8C" _bl_90769844-e72f-40fc-b290-c337320e18c4>
...
</fluent-card>

๊ทธ๋ฆฌ๊ณ  ์Šคํƒ€์ผ์€
| https://localhost:7061/BlazorApp33.styles.css

fluent-card[b-63vyab3aqy] {
    --card-height: 400px;
    --card-width: 500px;
    padding: 20px;
    margin: 12px;
}
...

๋กœ ๋งž์ง€๋ฅผ ์•Š๋„ค์š”? ์•„๋งˆ๋„ ์ž์ฒด ์‹œ์Šคํ…œ์„ ์ด์šฉํ•˜๋Š” ๋“ฏ ํ•˜๋ฉฐ ๊ทธ ์‹œ์Šคํ…œ์— ๋งž๊ฒŒ ์Šคํƒ€์ผ์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

4๊ฐœ์˜ ์ข‹์•„์š”

์ •๋ฆฌ

Fast ๋ฐ Fast Blazor๋Š” (ํŠนํžˆ Flast Blazor๋Š” Fast๊ฐ€ ์กด์†ํ•˜๋Š” ํ•œ) Microsoft๊ฐ€ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ ์šฉํ•ด ๋ณผ๋งŒํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ํŠนํžˆ Fast๋Š” GitHub์—์„œ 8k์˜ ์ง€์ง€๋ฅผ ๋ฐ›๊ณ  ์žˆ๋Š” ์ ๋„ ์ธ์ƒ์ ์ž…๋‹ˆ๋‹ค.

Blazor์—์„œ ์‚ฌ์šฉํ•˜๋Š” Fast๋Š” ๋‹ค๋ฅธ Blazor ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํŠน๋ณ„ํžˆ ๋‹ค๋ฅธ ๋Š๋‚Œ์€ ์—†์—ˆ์ง€๋งŒ ์•„๋งˆ๋„ Fast์˜ ์ดํ•ด๋„๊ฐ€ ๋‚ฎ์•„์„œ ์ƒ๊ธฐ๋Š” ์‹œ๊ฐ์— ์˜ํ•œ ๊ฒƒ์œผ๋กœ ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค. ์–ด์จŒ๋“  Fast Blazor๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” ์—ฌํƒ€ Blazor ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ๊ฐ์œผ๋กœ ๊ฑฐ์˜ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ ๋Œ€๋ถ€๋ถ„์˜ ๊ถ๊ธˆ์ฆ์€ ๋‹ค์Œ์˜ ๋ฐ๋ชจ๋ฅผ ํ†ตํ•ด ์ฐพ๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://brave-cliff-0c0c93310.azurestaticapps.net/

CSS ๊ฒฉ๋ฆฌ์˜ ๊ฒฝ์šฐ ์ •ํ™•ํ•œ ์›์ธ์€ ์ฐพ์ง€ ๋ชปํ–ˆ์œผ๋‚˜ Blazor ์ž์ฒด์˜ ๋ฌธ์ œ์™€ ์—ฐ๊ด€์ด ์žˆ๋Š” ๋“ฏ ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. Fast Blazor์˜ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ณ„๊ฐœ์˜ CSS ๊ฒฉ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋‚˜๋งŒ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ Fast ์ปดํฌ๋„ŒํŠธ์˜์— ์Šคํƒ€์ผ์„ ์ ์šฉํ•  ์ˆ˜ ์—†์—ˆ๋Š”๋ฐ ์ง€๊ธˆ์€ ์ด๋ถ€๋ถ„์ด ์ค‘์š”ํ•˜์ง€๋Š” ์•Š์œผ๋ฏ€๋กœ ๊ธธ๊ฒŒ ํ™•์ธ ํ›„ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์ฐพ์œผ๋ฉด ๋ง๊ธ€์„ ๋‹ฌ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ ˆ์ด์•„์›ƒ ์‹œ์Šคํ…œ์€ Lab์˜ Stack์„ ์‚ฌ์šฉํ•ด์„œ ์ ‘๊ทผํ•˜๊ณ  ์ข€ ๋” ๋‹ค์–‘ํ•œ ๊ตฌ์„ฑ์€ Stack์˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๋งŒ๋“ค์–ด๋‚˜๊ฐ€์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ๋ ˆ์ด์•„์›ƒ์€ Stack๋งŒ์œผ๋กœ๋„ ๊ฐ€๋Šฅํ•  ๊ฒƒ ๊ฐ™์•„ ๋ณด์˜€์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ ๋ฐ˜์‘ํ˜•๋„ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ด๊ฒƒ ์—ญ์‹œ ์ฐจ์ฐจ ๋‚˜๊ฐ€๋ฉฐ ์‹ค์ œ ์ ์šฉํ–ˆ์„ ๋•Œ์˜ ์†”๋ฃจ์…˜์„ ๋Œ“๊ธ€๋กœ ๋‹ฌ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

5๊ฐœ์˜ ์ข‹์•„์š”

@dimohy ๋‹˜์˜ Slog ๋•๋ถ„์— Fluent UI Blazor๋ฅผ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ„๊ฒฐํ•˜๊ณ  ์ข‹์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. web component๋„ ์•Œ๊ฒŒ๋˜๊ณ  fluent ui๊ฐ€ blazor๋กœ ํฌํŒ…๋œ ๋ถ€๋ถ„๋„ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. design token์€ ์‰ฝ๊ฒŒ ์ ์‘ํ•˜๊ธฐ ์–ด๋ ค์›Œ์„œ css๋ฅผ ํ•ธ๋“ค๋ง ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ…Œ์ŠคํŠธ ์ค‘์ž…๋‹ˆ๋‹ค.

tailwindcss์™€ fluent ui๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.
๊ตณ์ด tailwindcss๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ๊ณ„์† ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋‹ˆ ์†์— ์ต์–ด์„œ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค.

FluentCard๋Š” ๊ฐ„๋‹จํ•œ ์ปดํฌ๋„ŒํŠธ๋ผ Class๋ฅผ ํ†ตํ•ด tailwindcss ์ ์šฉ์ด ์‰ฌ์› ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” FluentButton์€ ๋ Œ๋”๋ง ๋œ๊ฒƒ์„ ๋ณด๋ฉด Child Element๋กœ button ํƒœ๊ทธ๊ฐ€ ๋“ค์–ด๊ฐ€ ์žˆ์–ด์„œ
fluent-button ํƒœ๊ทธ์— css๋ฅผ ์ ์šฉํ•˜๊ธฐ ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ , css ๊ฒฉ๋ฆฌ์™€ ๋น„์Šทํ•œ ํšจ๊ณผ๋ฅผ ์–ป๊ณ ์ž ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

(์ค‘๋žตโ€ฆ) ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  1. tailwindcss ์„ค์ •

  2. postcss ๋ฐ autoprefixer ์„ค์น˜

  3. postcss-import์™€ postcss-easy-import ์„ค์น˜

npm install -D postcss-import postcss-easy-import
  1. postcss.config.js ์„ค์ •
module.exports = {
    plugins: [
        require('postcss-easy-import'),
        require('tailwindcss'),
        require('autoprefixer'),
    ]
}
  1. package.json ์„ค์ •
  "scripts": {
    "build": "postcss ./Src/base.styles.css -o ./wwwroot/css/StyleSheet.css",
    "watch": "postcss ./Src/base.styles.css -o ./wwwroot/css/StyleSheet.css --watch --verbose"
  }
  1. base.styles.css ํŒŒ์ผ ์ƒ์„ฑ
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

@import './tag.styles.css';

/* postcss easy import */
@import '../Pages/**/*.razor.css';
  1. tag.styles.css ํŒŒ์ผ ์ƒ์„ฑ
fluent-card {
    @apply border rounded-none shadow-none;
}

fluent-button {
    @apply border-0 rounded-none shadow-none;
}
  1. /Pages/Index.razor
<FluentCard Class="w-[300px] h-[300px] text-red-500">
  <h2>Hello World!</h2>
  <FluentButton id="test">Click Me</FluentButton>
</FluentCard>
  1. /Pages/Index.razor.css
#test::part(control) {
    @apply border text-red-500 bg-white text-[20px] hover:text-white hover:bg-red-500;
    --neutral-fill-hover: initial;
}
  1. wwwroot/css/StyleSheet.css ํŒŒ์ผ ์ƒ์„ฑ
npm run build

์ผ๋ถ€๋งŒ ํ…Œ์ŠคํŠธํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.
๋‚ด์šฉ์„ ์˜ฌ๋ฆฌ๋Š”์ค‘ ๋“œ๋Š” ์ƒ๊ฐ์€ ๊ตณ์ด ์ด๋ ‡๊ฒŒ๊นŒ์ง€ ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ๋˜๋‚˜ ์‹ถ์Šต๋‹ˆ๋‹ค.

5๊ฐœ์˜ ์ข‹์•„์š”

์•„๋‹™๋‹ˆ๋‹ค. ํ›Œ๋ฅญํ•˜๋„ค์š”โ€ฆ ๊ด€๋ จ ๊ฒฝํ—˜์„ ๋ธ”๋กœ๊ทธ ๊ธ€๋กœ ๊ณต์œ  ์ฃผ์‹œ๋ฉด ๋„์›€์ด ๋งŽ์ด ๋  ๋“ฏ ํ•ฉ๋‹ˆ๋‹ค.

3๊ฐœ์˜ ์ข‹์•„์š”

์š”์ปจ๋Œ€ ์ต์ˆ™ํ•ด์ง€๊ธฐ ํŽธํ•œ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ๋งŒ ์ œ๊ณตํ•˜๊ณ ,
์˜ˆ์˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฑด ๊ฒฐ๊ตญ css๋กœ ์žก์•„์ค˜์•ผ ํ•˜๋Š”๊ฑฐ๊ตฐ์š”?

์Œ, ์˜คํžˆ๋ ค ๊ทธ๊ฒŒ ๋” ๊น”๋”ํ•˜๊ฒŒ ๋ณด์ผ ์ˆ˜๋„ ์žˆ๊ฒ ๋„ค์š”.
์ • ์•ˆ๋˜๋ฉด ์˜ˆ์œ css ๊ตฌํ•ด๋‹ค ๋ถ™์—ฌ๋ฒ„๋ ค๋„ ๋˜๊ณ ,
๋‹จโ€ฆ @_jeonghwan ๋‹˜๊ป˜์„œ ์ •๋ฆฌํ•ด์ฃผ์‹  ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ๊ฒ ๋„ค์š”.

2๊ฐœ์˜ ์ข‹์•„์š”

CSS์—์„œ flex์™€ grid๊ฐ€ ์–ด๋Š์ •๋„ ์ด์ˆ™ํ•ด์ง€๋‹ˆ <Stack> ๋“ฑ์˜ ๋ ˆ์ด์•„์›ƒ ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ฑฐ์ถ”์žฅํ•ด์กŒ์Šต๋‹ˆ๋‹ค. class ๋˜๋Š” style์ด ์•„๋‹Œ ๋ณ„๋„์˜ ์ปดํฌ๋„ŒํŠธ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ด์„œ ๊ตฌ์กฐ๊ฐ€ ์ข€ ๋” ๋ณต์žกํ•ด์ง€๋Š” ์ ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ •๋„ ๋˜๋‹ˆ HTML-CSS ์‚ฌ์ƒ โ€“ ๋ฌธ์„œ์™€ ์Šคํƒ€์ผ์„ ๊ตฌ๋ณ„ํ•˜๋Š” ์ ‘๊ทผ๋ฒ•์ด XAML ๊ตฌ์กฐ ๋ณด๋‹ค ์ข‹์•„๋ณด์ด๋Š” ์ ๋„ ์ƒ๊น๋‹ˆ๋‹ค. (๋ ˆ์ด์•„์›ƒ์„ ๋น ๋ฅด๊ฒŒ ํƒœ๊ทธ๋กœ ์žก๊ณ  ์Šคํƒ€์ผ์„ ๋จน์—ฌ๊ฐ€๋Š” ์žฌ๋ฏธ๋„ ์ข€ ์ฐจ์ด๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค)

4๊ฐœ์˜ ์ข‹์•„์š”

์ œ๊ฐ€ ์„ธํŒ…์„ ์ž˜ ๋ชป ํ•ด์„œ ๊ทธ๋Ÿฐ์ง€๋Š” ๋ชฐ๋ผ๋„,
๋‹ท๋„ท 8.0์—์„œ ์ƒˆ๋กœ ๋ฐ”๋€ blazor์˜ ๊ธฐ๋ณธ template๊ณผ ํ˜ธํ™˜์ด ๋˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์•„์š”.

์‹ฌ์ง€์–ด ๊ฐ™์€ ๋Ÿฐํƒ€์ž„ ์กฐ๊ฑด ํ•˜์—์„œ, fast ์ „์šฉ, ์ฆ‰ FluentUI ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ƒ์„ฑํ•˜๋ฉด ์ž˜ ์ž‘๋™ ํ•ฉ๋‹ˆ๋‹ค๋งŒ,
8 ๋ฒ„์ „์ด ์•„๋‹ˆ์—ˆ์„ ๋•Œ์˜ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ์ƒ์„ฑํ•ด์„œ ๊ทธ๋Ÿฐ๊ฐ€ ๋ด์š”.

2๊ฐœ์˜ ์ข‹์•„์š”

์ œ๊ฐ€ ํ…Œ์ŠคํŠธ ํ–ˆ์„ ๋•Œ๋Š” ์ž˜ ๋˜์—ˆ๋Š”๋ฐ์š”, ๋„์›€์„ ๋“œ๋ฆด ์ˆ˜ ์žˆ๋„๋ก ํ”„๋กœ์ ํŠธ๋ฅผ ๊ณต์œ  ๊ฐ€๋Šฅ ํ• ๊นŒ์š”?

3๊ฐœ์˜ ์ข‹์•„์š”