Files
CustomBranding/README.md
Torsten Brendgen 490e9adbd8 feat: Add custom branding functionality with CSS and JSON configuration
- Introduced custom branding CSS styles in `custom-branding.css`.
- Created example JSON configuration for custom branding in `custom-branding.example.json`.
- Implemented branding configuration logic in `BrandingConfig.ts` to normalize and validate branding settings.
- Developed CSS loader to manage loading and unloading of custom stylesheets in `BrandingCssLoader.ts`.
- Added DOM rendering capabilities for branding elements in `BrandingDomRenderer.ts`.
- Defined types and interfaces for branding elements and configurations in `BrandingTypes.ts`.
- Included localization support for German in `de-de.js`.
- Added unit tests for branding configuration, CSS loader, and DOM renderer.
- Validated project structure and static assets with new validation scripts.
2026-07-20 22:55:47 +02:00

7.3 KiB

CustomBranding

CustomBranding 3.0 ist ein zentraler SPFx-1.4.1-Application-Customizer für SharePoint Server Subscription Edition. Die Solution lädt freigegebene Stylesheets und rendert eine kontrollierte Komponentenstruktur im oberen oder unteren SharePoint-Placeholder. Moderne und klassische Seiten verwenden dieselben ClientSideComponentProperties.

Die Konfiguration liegt in genau einer SPSite.UserCustomAction pro Site Collection. Es werden weder eine versteckte Liste noch ein Property Bag benötigt. Dadurch gilt das Branding automatisch für das Root Web, vorhandene Subwebs und später angelegte Subwebs.

Architektur

App Catalog
└── zentral bereitgestelltes SPFx-Bundle

Site Collection
├── SPSite.UserCustomAction mit ClientSideComponentProperties
├── moderne Seiten: SPFx Application Customizer
└── klassische Seiten: optionaler SPSite ScriptLink

CustomHeader
├── CustomBrandingTopHost
└── MegaMenuHost (wird nicht verändert)

CustomFooter
└── CustomBrandingBottomHost

CustomBranding verändert nur seine eigenen Host-Elemente. Das MegaMenu und andere Erweiterungen im selben Placeholder bleiben bei Navigation und erneutem Rendern erhalten.

Voraussetzungen und Build

  • SharePoint Server Subscription Edition
  • SPFx 1.4.1
  • Node.js 8.17.0
  • npm 6.13.4
  • lokale Gulp-Version 3.9.1
npm install
npm test
npm run package

npm run package führt zuerst die Tests und den Classic-Build aus. Das SharePoint-Paket entsteht unter sharepoint/solution/custom-branding.sppkg. Die Classic-Dateien liegen anschließend unter classic/dist.

Die alte SPFx-Toolchain lässt sich mit aktuellen Node-Versionen nicht zuverlässig paketieren. Der abschließende Ship-Build muss deshalb mit Node.js 8.17.0 erfolgen.

Installation und zentrale Registrierung

  1. custom-branding.sppkg im App Catalog hochladen oder ersetzen und zentral bereitstellen.
  2. Das Skript in der SharePoint Management Shell ausführen.
  3. Eine moderne Seite mit Strg+F5 neu laden.
.\deployment\add-custombranding.ps1 `
  -SiteUrl 'http://clshp001/sites/portal' `
  -CssPath '~sitecollection/SiteAssets/branding/custom-branding.css'

Das Skript arbeitet idempotent: Es erhält vorhandene Properties, entfernt doppelte oder alte web-scoped Registrierungen und erzeugt genau eine site-scoped Action. Ein bewusstes Zurücksetzen erfolgt nur mit -ResetConfiguration.

Weitere Optionen:

# Debug-Ausgaben einschalten und einen externen HTTPS-CSS-Host freigeben
.\deployment\add-custombranding.ps1 `
  -SiteUrl 'http://clshp001/sites/portal' `
  -EnableDebug `
  -AllowedCssHost 'cdn.example.org'

# Extension deaktivieren, Konfiguration aber erhalten
.\deployment\add-custombranding.ps1 `
  -SiteUrl 'http://clshp001/sites/portal' `
  -Disable

Konfiguration

Das aktuelle Konfigurationsschema hat die Version 2:

{
  "schemaVersion": 2,
  "enabled": true,
  "debug": false,
  "allowedCssHosts": [],
  "cssfiles": [
    {
      "path": "~sitecollection/SiteAssets/branding/custom-branding.css",
      "media": "all"
    }
  ],
  "placeholdertop": {
    "elements": [
      {
        "type": "section",
        "attributes": {
          "class": "custom-branding-banner",
          "role": "region",
          "aria-label": "Portalhinweis"
        },
        "children": [
          {
            "type": "strong",
            "content": "Willkommen im Portal"
          }
        ]
      }
    ]
  },
  "placeholderbottom": {
    "elements": []
  }
}

Bestehende 1.x-Konfigurationen mit einem Root-Array elements werden weiterhin als Top-Inhalt gelesen. Unbekannte Properties ignoriert die Runtime. Das vollständige Beispiel liegt unter examples/custom-branding.example.json.

Sicherheitsgrenzen

Erlaubte Elemente:

div, span, p, a, button, img, h1, h2, h3, strong, em, nav, section

Attribute und Styles werden pro Element über feste Allowlisten geprüft. Insbesondere gelten folgende Regeln:

  • script, iframe, alle on*-Attribute, javascript:, data: und CSS mit url() oder expression() werden verworfen.
  • Bilder benötigen immer ein alt; dekorative Bilder verwenden alt: "".
  • Leere Links und Buttons sind nicht erlaubt; Buttons erhalten immer type="button".
  • Links mit target="_blank" erhalten automatisch rel="noopener noreferrer".
  • Relative CSS-Pfade und CSS derselben Origin sind erlaubt. Fremde Quellen benötigen HTTPS und einen Eintrag in allowedCssHosts.
  • Maximal 20 Stylesheets, 200 Elemente, acht Ebenen und 100.000 Zeichen Konfiguration werden verarbeitet.

Unsichere Teilwerte werden kontrolliert verworfen, ohne die SharePoint-Seite zu blockieren. Details erscheinen nur bei debug: true in der Browserkonsole mit dem Präfix [CustomBranding].

Classic SharePoint

Der SPFx Application Customizer selbst läuft nicht auf klassischen Seiten. Version 3.0 enthält deshalb eine separate ES5-Runtime mit demselben Sicherheits- und Konfigurationsmodell.

npm run build:classic

Danach classic/dist/custom-branding-classic.js nach beispielsweise /SiteAssets/custom-branding/ hochladen und zentral registrieren:

.\deployment\add-custombranding.ps1 `
  -SiteUrl 'http://clshp001/sites/portal' `
  -ClassicScriptUrl '~sitecollection/SiteAssets/custom-branding/custom-branding-classic.js'

Der site-scoped ScriptLink gilt auch für später angelegte Subwebs. Entfernen lässt er sich mit -RemoveClassicScriptLink. Weitere Hinweise stehen in classic/classic-deployment.md.

PortalSettings v3

CustomBranding funktioniert unabhängig von PortalSettings. Das geplante PortalSettings-v3-Webpart kann die Action anhand folgender Werte erkennen und die Properties schemaerhaltend bearbeiten:

  • Component ID: 035ba968-6488-4d42-86b3-0470ffcc95b9
  • Location: ClientSideExtension.ApplicationCustomizer
  • Scope: SPSite.UserCustomActions
  • Schema: schemaVersion: 2

Ein Editor muss unbekannte Properties erhalten und vor dem Speichern dieselben Element-, Attribut-, URL- und CSS-Grenzen beachten.

Diagnose

Zentrale Registrierung prüfen:

$site = Get-SPSite 'http://clshp001/sites/portal'
$site.UserCustomActions | Where-Object {
  $_.ClientSideComponentId -eq [Guid]'035ba968-6488-4d42-86b3-0470ffcc95b9'
} | Select-Object Id, Title, Location, ClientSideComponentProperties
$site.Dispose()

Browserkonsole auf einer modernen Seite:

performance.getEntriesByType('resource')
  .map(function (entry) { return entry.name; })
  .filter(function (url) { return url.toLowerCase().indexOf('custom-branding') >= 0; });

({
  header: !!document.getElementById('CustomHeader'),
  branding: !!document.getElementById('CustomBrandingTopHost'),
  megaMenu: !!document.getElementById('MegaMenuHost')
});

Classic-Diagnose:

typeof window.CustomBrandingClassic
window.CustomBrandingClassic.reload()

Upgrade von 1.x

  1. Paket im App Catalog durch Version 3.0.0.0 ersetzen und bereitstellen.
  2. add-custombranding.ps1 einmal pro Site Collection ausführen; bestehende Properties bleiben erhalten.
  3. Moderne und gegebenenfalls klassische Seiten testen.
  4. Erst nach erfolgreicher Abnahme alte web-scoped Aktionen als bereinigt bestätigen.

Ein Downgrade sollte nur zusammen mit einer Sicherung der ClientSideComponentProperties erfolgen.