Index: resources/data/validator/geometry.mapcss
===================================================================
--- resources/data/validator/geometry.mapcss	(revision 17447)
+++ resources/data/validator/geometry.mapcss	(working copy)
@@ -200,6 +200,10 @@
   throwWarning: tr("Water area inside water area");
 }
 
+area:closed:areaStyle[landuse=residential] ⧉o area[building][building!~/no|entrance/] {
+  throwWarning: tr("Building partly outside of residential area");
+}
+
 area:closed:areaStyle ⧉ area:closed:areaStyle {
   throwOther: tr("Overlapping Areas");
 }
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(revision 17447)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(working copy)
@@ -217,6 +217,7 @@
 |   < SUPERSET_OR_EQUAL: "⊇" >
 |   < NOT_SUPERSET_OR_EQUAL: "⊉" >
 |   < CROSSING: "⧉" >
+|   < CROSSING_OUTSIDE: "⧉o" >
 |   < PERCENT: "%" >
 |   < COMMENT_START: "/*" > : COMMENT
 |   < UNEXPECTED_CHAR : ~[] > // avoid TokenMgrErrors because they are hard to recover from
@@ -633,6 +634,8 @@
                 <NOT_SUPERSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.NOT_SUPERSET_OR_EQUAL; }
             |
                 <CROSSING> { type = Selector.ChildOrParentSelectorType.CROSSING; }
+            |
+                <CROSSING_OUTSIDE> { type = Selector.ChildOrParentSelectorType.CROSSING_OUTSIDE; }
             )
             w()
         |
Index: src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 17447)
+++ src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(working copy)
@@ -126,7 +126,7 @@
      * @see ChildOrParentSelector
      */
     enum ChildOrParentSelectorType {
-        CHILD, PARENT, SUBSET_OR_EQUAL, NOT_SUBSET_OR_EQUAL, SUPERSET_OR_EQUAL, NOT_SUPERSET_OR_EQUAL, CROSSING, SIBLING,
+        CHILD, PARENT, SUBSET_OR_EQUAL, NOT_SUBSET_OR_EQUAL, SUPERSET_OR_EQUAL, NOT_SUPERSET_OR_EQUAL, CROSSING, SIBLING, CROSSING_OUTSIDE,
     }
 
     /**
@@ -318,17 +318,19 @@
             };
         }
 
-        private final class CrossingFinder extends AbstractFinder {
+        private class CrossingFinder extends AbstractFinder {
 
             private final String layer;
             private Area area;
             /** Will contain all way segments, grouped by cells */
             Map<Point2D, List<WaySegment>> cellSegments;
+            private final boolean markOutsideArea;
 
-            private CrossingFinder(Environment e) {
+            private CrossingFinder(Environment e, boolean markOutside) {
                 super(e);
                 CheckParameterUtil.ensureThat(isArea(e.osm), "Only areas are supported");
                 layer = OsmUtils.getLayer(e.osm);
+                this.markOutsideArea = markOutside;
             }
 
             private Area getAreaEastNorth(IPrimitive p, Environment e) {
@@ -398,10 +400,16 @@
                         if (e.intersections == null) {
                             e.intersections = new HashMap<>();
                         }
-                        e.intersections.put(p, is.b);
+                        final Area hiliteArea;
+                        if (markOutsideArea) {
+                            hiliteArea = new Area(area);
+                            hiliteArea.subtract(is.b);
+                        } else {
+                            hiliteArea = is.b;
+                        }
+                        e.intersections.put(p, hiliteArea);
                     }
                 }
-
             }
 
             private void useFindCrossings(IPrimitive p) {
@@ -545,10 +553,11 @@
                 visitBBox(e, insideOrEqualFinder);
                 return ChildOrParentSelectorType.SUPERSET_OR_EQUAL == type ? e.children != null : e.children == null;
 
-            } else if (ChildOrParentSelectorType.CROSSING == type) {
+            } else if (ChildOrParentSelectorType.CROSSING == type || ChildOrParentSelectorType.CROSSING_OUTSIDE == type) {
                 e.parent = e.osm;
                 if (e.osm.getDataSet() != null && isArea(e.osm)) {
-                    final CrossingFinder crossingFinder = new CrossingFinder(e);
+                    boolean markOutside = ChildOrParentSelectorType.CROSSING_OUTSIDE == type;
+                    final CrossingFinder crossingFinder = new CrossingFinder(e, markOutside);
                     visitBBox(e, crossingFinder);
                     return e.children != null;
                 }
